ThirdPartyMonitor.php 11 KB

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