ThirdPartyMonitor.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. <?php
  2. namespace App\Module\ThirdParty\Models;
  3. use UCore\ModelCore;
  4. use Illuminate\Database\Eloquent\Relations\BelongsTo;
  5. /**
  6. * 第三方服务监控记录模型
  7. *
  8. * @property int $id 主键ID
  9. * @property int $service_id 服务ID
  10. * @property string $check_type 检查类型
  11. * @property string $status 检查状态
  12. * @property int|null $response_time 响应时间
  13. * @property int|null $status_code HTTP状态码
  14. * @property string|null $error_message 错误信息
  15. * @property array|null $details 详细信息
  16. * @property \Carbon\Carbon $checked_at 检查时间
  17. */
  18. class ThirdPartyMonitor extends ModelCore
  19. {
  20. /**
  21. * 数据表名
  22. *
  23. * @var string
  24. */
  25. protected $table = 'thirdparty_monitors';
  26. /**
  27. * 禁用updated_at字段
  28. *
  29. * @var bool
  30. */
  31. public $timestamps = false;
  32. // field start
  33. /**
  34. * 可批量赋值的属性
  35. *
  36. * @var array
  37. */
  38. // attrlist start
  39. protected $fillable = [
  40. 'service_id',
  41. 'check_type',
  42. 'status',
  43. 'response_time',
  44. 'status_code',
  45. 'error_message',
  46. 'details',
  47. 'checked_at',
  48. ];
  49. // attrlist end
  50. // field end
  51. /**
  52. * 属性类型转换
  53. *
  54. * @var array
  55. */
  56. protected $casts = [
  57. 'service_id' => 'integer',
  58. 'response_time' => 'integer',
  59. 'status_code' => 'integer',
  60. 'details' => 'array',
  61. 'checked_at' => 'datetime',
  62. ];
  63. /**
  64. * 检查类型常量
  65. */
  66. const CHECK_TYPE_HEALTH = 'health';
  67. const CHECK_TYPE_PERFORMANCE = 'performance';
  68. const CHECK_TYPE_AVAILABILITY = 'availability';
  69. /**
  70. * 检查状态常量
  71. */
  72. const STATUS_SUCCESS = 'success';
  73. const STATUS_WARNING = 'warning';
  74. const STATUS_ERROR = 'error';
  75. const STATUS_TIMEOUT = 'timeout';
  76. const STATUS_UNKNOWN = 'unknown';
  77. /**
  78. * 获取检查类型标签
  79. *
  80. * @return string
  81. */
  82. public function getCheckTypeLabel(): string
  83. {
  84. return match ($this->check_type) {
  85. self::CHECK_TYPE_HEALTH => '健康检查',
  86. self::CHECK_TYPE_PERFORMANCE => '性能检查',
  87. self::CHECK_TYPE_AVAILABILITY => '可用性检查',
  88. default => '未知类型',
  89. };
  90. }
  91. /**
  92. * 获取状态标签
  93. *
  94. * @return string
  95. */
  96. public function getStatusLabel(): string
  97. {
  98. return match ($this->status) {
  99. self::STATUS_SUCCESS => '成功',
  100. self::STATUS_WARNING => '警告',
  101. self::STATUS_ERROR => '错误',
  102. self::STATUS_TIMEOUT => '超时',
  103. self::STATUS_UNKNOWN => '未知',
  104. default => '未知状态',
  105. };
  106. }
  107. /**
  108. * 获取状态颜色
  109. *
  110. * @return string
  111. */
  112. public function getStatusColor(): string
  113. {
  114. return match ($this->status) {
  115. self::STATUS_SUCCESS => 'success',
  116. self::STATUS_WARNING => 'warning',
  117. self::STATUS_ERROR => 'danger',
  118. self::STATUS_TIMEOUT => 'danger',
  119. self::STATUS_UNKNOWN => 'secondary',
  120. default => 'secondary',
  121. };
  122. }
  123. /**
  124. * 获取状态图标
  125. *
  126. * @return string
  127. */
  128. public function getStatusIcon(): string
  129. {
  130. return match ($this->status) {
  131. self::STATUS_SUCCESS => 'fa-check-circle',
  132. self::STATUS_WARNING => 'fa-exclamation-triangle',
  133. self::STATUS_ERROR => 'fa-times-circle',
  134. self::STATUS_TIMEOUT => 'fa-clock',
  135. self::STATUS_UNKNOWN => 'fa-question-circle',
  136. default => 'fa-question-circle',
  137. };
  138. }
  139. /**
  140. * 检查是否成功
  141. *
  142. * @return bool
  143. */
  144. public function isSuccessful(): bool
  145. {
  146. return $this->status === self::STATUS_SUCCESS;
  147. }
  148. /**
  149. * 检查是否有问题
  150. *
  151. * @return bool
  152. */
  153. public function hasIssue(): bool
  154. {
  155. return in_array($this->status, [self::STATUS_WARNING, self::STATUS_ERROR, self::STATUS_TIMEOUT]);
  156. }
  157. /**
  158. * 检查是否为严重问题
  159. *
  160. * @return bool
  161. */
  162. public function isCritical(): bool
  163. {
  164. return in_array($this->status, [self::STATUS_ERROR, self::STATUS_TIMEOUT]);
  165. }
  166. /**
  167. * 获取响应时间(秒)
  168. *
  169. * @return float
  170. */
  171. public function getResponseTimeInSeconds(): float
  172. {
  173. return $this->response_time ? $this->response_time / 1000 : 0;
  174. }
  175. /**
  176. * 获取格式化的响应时间
  177. *
  178. * @return string
  179. */
  180. public function getFormattedResponseTime(): string
  181. {
  182. if (!$this->response_time) {
  183. return '-';
  184. }
  185. if ($this->response_time < 1000) {
  186. return $this->response_time . 'ms';
  187. }
  188. return number_format($this->getResponseTimeInSeconds(), 2) . 's';
  189. }
  190. /**
  191. * 获取性能评级
  192. *
  193. * @return string
  194. */
  195. public function getPerformanceGrade(): string
  196. {
  197. if (!$this->response_time) {
  198. return 'N/A';
  199. }
  200. if ($this->response_time <= 200) {
  201. return 'A';
  202. } elseif ($this->response_time <= 500) {
  203. return 'B';
  204. } elseif ($this->response_time <= 1000) {
  205. return 'C';
  206. } elseif ($this->response_time <= 2000) {
  207. return 'D';
  208. } else {
  209. return 'F';
  210. }
  211. }
  212. /**
  213. * 获取性能评级颜色
  214. *
  215. * @return string
  216. */
  217. public function getPerformanceGradeColor(): string
  218. {
  219. return match ($this->getPerformanceGrade()) {
  220. 'A' => 'success',
  221. 'B' => 'info',
  222. 'C' => 'warning',
  223. 'D' => 'danger',
  224. 'F' => 'dark',
  225. default => 'secondary',
  226. };
  227. }
  228. /**
  229. * 获取详细信息中的特定值
  230. *
  231. * @param string $key
  232. * @param mixed $default
  233. * @return mixed
  234. */
  235. public function getDetail(string $key, $default = null)
  236. {
  237. return $this->details[$key] ?? $default;
  238. }
  239. /**
  240. * 获取监控摘要
  241. *
  242. * @return array
  243. */
  244. public function getSummary(): array
  245. {
  246. return [
  247. 'check_type' => $this->getCheckTypeLabel(),
  248. 'status' => $this->getStatusLabel(),
  249. 'response_time' => $this->getFormattedResponseTime(),
  250. 'performance_grade' => $this->getPerformanceGrade(),
  251. 'checked_at' => $this->checked_at->format('Y-m-d H:i:s'),
  252. ];
  253. }
  254. /**
  255. * 关联第三方服务
  256. *
  257. * @return BelongsTo
  258. */
  259. public function service(): BelongsTo
  260. {
  261. return $this->belongsTo(ThirdPartyService::class, 'service_id');
  262. }
  263. /**
  264. * 创建监控记录
  265. *
  266. * @param array $data
  267. * @return static
  268. */
  269. public static function createMonitor(array $data): static
  270. {
  271. // 自动设置检查时间
  272. if (!isset($data['checked_at'])) {
  273. $data['checked_at'] = now();
  274. }
  275. // 根据响应时间和状态码自动判断状态
  276. if (!isset($data['status'])) {
  277. if (isset($data['status_code'])) {
  278. if ($data['status_code'] >= 200 && $data['status_code'] < 300) {
  279. $data['status'] = self::STATUS_SUCCESS;
  280. } elseif ($data['status_code'] >= 300 && $data['status_code'] < 400) {
  281. $data['status'] = self::STATUS_WARNING;
  282. } else {
  283. $data['status'] = self::STATUS_ERROR;
  284. }
  285. } elseif (isset($data['response_time'])) {
  286. if ($data['response_time'] > 10000) { // 超过10秒认为超时
  287. $data['status'] = self::STATUS_TIMEOUT;
  288. } else {
  289. $data['status'] = self::STATUS_SUCCESS;
  290. }
  291. } else {
  292. $data['status'] = self::STATUS_UNKNOWN;
  293. }
  294. }
  295. return static::create($data);
  296. }
  297. /**
  298. * 按服务查询
  299. *
  300. * @param \Illuminate\Database\Eloquent\Builder $query
  301. * @param int $serviceId
  302. * @return \Illuminate\Database\Eloquent\Builder
  303. */
  304. public function scopeByService($query, int $serviceId)
  305. {
  306. return $query->where('service_id', $serviceId);
  307. }
  308. /**
  309. * 按检查类型查询
  310. *
  311. * @param \Illuminate\Database\Eloquent\Builder $query
  312. * @param string $checkType
  313. * @return \Illuminate\Database\Eloquent\Builder
  314. */
  315. public function scopeByCheckType($query, string $checkType)
  316. {
  317. return $query->where('check_type', $checkType);
  318. }
  319. /**
  320. * 按状态查询
  321. *
  322. * @param \Illuminate\Database\Eloquent\Builder $query
  323. * @param string $status
  324. * @return \Illuminate\Database\Eloquent\Builder
  325. */
  326. public function scopeByStatus($query, string $status)
  327. {
  328. return $query->where('status', $status);
  329. }
  330. /**
  331. * 查询成功的记录
  332. *
  333. * @param \Illuminate\Database\Eloquent\Builder $query
  334. * @return \Illuminate\Database\Eloquent\Builder
  335. */
  336. public function scopeSuccessful($query)
  337. {
  338. return $query->where('status', self::STATUS_SUCCESS);
  339. }
  340. /**
  341. * 查询有问题的记录
  342. *
  343. * @param \Illuminate\Database\Eloquent\Builder $query
  344. * @return \Illuminate\Database\Eloquent\Builder
  345. */
  346. public function scopeWithIssues($query)
  347. {
  348. return $query->whereIn('status', [self::STATUS_WARNING, self::STATUS_ERROR, self::STATUS_TIMEOUT]);
  349. }
  350. /**
  351. * 查询严重问题的记录
  352. *
  353. * @param \Illuminate\Database\Eloquent\Builder $query
  354. * @return \Illuminate\Database\Eloquent\Builder
  355. */
  356. public function scopeCritical($query)
  357. {
  358. return $query->whereIn('status', [self::STATUS_ERROR, self::STATUS_TIMEOUT]);
  359. }
  360. /**
  361. * 按时间范围查询
  362. *
  363. * @param \Illuminate\Database\Eloquent\Builder $query
  364. * @param string $startDate
  365. * @param string $endDate
  366. * @return \Illuminate\Database\Eloquent\Builder
  367. */
  368. public function scopeDateRange($query, string $startDate, string $endDate)
  369. {
  370. return $query->whereBetween('checked_at', [$startDate, $endDate]);
  371. }
  372. /**
  373. * 获取所有检查类型
  374. *
  375. * @return array
  376. */
  377. public static function getCheckTypes(): array
  378. {
  379. return [
  380. self::CHECK_TYPE_HEALTH => '健康检查',
  381. self::CHECK_TYPE_PERFORMANCE => '性能检查',
  382. self::CHECK_TYPE_AVAILABILITY => '可用性检查',
  383. ];
  384. }
  385. /**
  386. * 获取所有状态
  387. *
  388. * @return array
  389. */
  390. public static function getStatuses(): array
  391. {
  392. return [
  393. self::STATUS_SUCCESS => '成功',
  394. self::STATUS_WARNING => '警告',
  395. self::STATUS_ERROR => '错误',
  396. self::STATUS_TIMEOUT => '超时',
  397. self::STATUS_UNKNOWN => '未知',
  398. ];
  399. }
  400. }