'date', 'hour' => 'integer', 'request_count' => 'integer', 'success_count' => 'integer', 'error_count' => 'integer', 'avg_response_time' => 'float', 'max_response_time' => 'float', 'min_response_time' => 'float', 'rate_limit_hits' => 'integer', 'unique_ips' => 'integer', 'error_details' => 'array', ]; /** * 默认值 * * @var array */ protected $attributes = [ 'request_count' => 0, 'success_count' => 0, 'error_count' => 0, 'avg_response_time' => 0, 'max_response_time' => 0, 'min_response_time' => 0, 'rate_limit_hits' => 0, 'unique_ips' => 0, ]; /** * 关联应用模型 * * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function app() { return $this->belongsTo(OpenApiApp::class, 'app_id', 'app_id'); } /** * 获取成功率 * * @return float */ public function getSuccessRateAttribute(): float { if ($this->request_count === 0) { return 0; } return round(($this->success_count / $this->request_count) * 100, 2); } /** * 获取错误率 * * @return float */ public function getErrorRateAttribute(): float { if ($this->request_count === 0) { return 0; } return round(($this->error_count / $this->request_count) * 100, 2); } /** * 获取限流命中率 * * @return float */ public function getRateLimitHitRateAttribute(): float { if ($this->request_count === 0) { return 0; } return round(($this->rate_limit_hits / $this->request_count) * 100, 2); } /** * 获取时间段标识 * * @return string */ public function getTimePeriodAttribute(): string { if ($this->hour !== null) { return $this->date->format('Y-m-d') . ' ' . sprintf('%02d:00', $this->hour); } return $this->date->format('Y-m-d'); } /** * 获取格式化的平均响应时间 * * @return string */ public function getFormattedAvgResponseTimeAttribute(): string { if ($this->avg_response_time < 1000) { return round($this->avg_response_time, 2) . 'ms'; } return round($this->avg_response_time / 1000, 2) . 's'; } /** * 更新统计数据 * * @param array $data * @return void */ public function updateStats(array $data): void { $this->increment('request_count', $data['request_count'] ?? 1); if (isset($data['success']) && $data['success']) { $this->increment('success_count'); } else { $this->increment('error_count'); } if (isset($data['response_time'])) { $this->updateResponseTime($data['response_time']); } if (isset($data['rate_limit_hit']) && $data['rate_limit_hit']) { $this->increment('rate_limit_hits'); } if (isset($data['unique_ip'])) { $this->updateUniqueIps($data['unique_ip']); } if (isset($data['error_details'])) { $this->updateErrorDetails($data['error_details']); } } /** * 更新响应时间统计 * * @param float $responseTime * @return void */ protected function updateResponseTime(float $responseTime): void { // 更新平均响应时间 $totalTime = $this->avg_response_time * ($this->request_count - 1) + $responseTime; $this->avg_response_time = $totalTime / $this->request_count; // 更新最大响应时间 if ($responseTime > $this->max_response_time) { $this->max_response_time = $responseTime; } // 更新最小响应时间 if ($this->min_response_time === 0 || $responseTime < $this->min_response_time) { $this->min_response_time = $responseTime; } $this->save(); } /** * 更新唯一IP统计 * * @param string $ip * @return void */ protected function updateUniqueIps(string $ip): void { // 这里可以使用Redis Set来精确统计唯一IP // 为了简化,这里只是增加计数 $this->increment('unique_ips'); } /** * 更新错误详情 * * @param array $errorDetails * @return void */ protected function updateErrorDetails(array $errorDetails): void { $currentDetails = $this->error_details ?? []; $errorCode = $errorDetails['code'] ?? 'unknown'; if (!isset($currentDetails[$errorCode])) { $currentDetails[$errorCode] = [ 'count' => 0, 'message' => $errorDetails['message'] ?? '', 'first_seen' => now()->toISOString(), ]; } $currentDetails[$errorCode]['count']++; $currentDetails[$errorCode]['last_seen'] = now()->toISOString(); $this->update(['error_details' => $currentDetails]); } /** * 按应用ID查询 * * @param \Illuminate\Database\Eloquent\Builder $query * @param string $appId * @return \Illuminate\Database\Eloquent\Builder */ public function scopeByApp($query, string $appId) { return $query->where('app_id', $appId); } /** * 按日期查询 * * @param \Illuminate\Database\Eloquent\Builder $query * @param string $date * @return \Illuminate\Database\Eloquent\Builder */ public function scopeByDate($query, string $date) { return $query->where('date', $date); } /** * 按日期范围查询 * * @param \Illuminate\Database\Eloquent\Builder $query * @param string $startDate * @param string $endDate * @return \Illuminate\Database\Eloquent\Builder */ public function scopeDateRange($query, string $startDate, string $endDate) { return $query->whereBetween('date', [$startDate, $endDate]); } /** * 按小时查询 * * @param \Illuminate\Database\Eloquent\Builder $query * @param int $hour * @return \Illuminate\Database\Eloquent\Builder */ public function scopeByHour($query, int $hour) { return $query->where('hour', $hour); } /** * 按接口端点查询 * * @param \Illuminate\Database\Eloquent\Builder $query * @param string $endpoint * @return \Illuminate\Database\Eloquent\Builder */ public function scopeByEndpoint($query, string $endpoint) { return $query->where('endpoint', $endpoint); } /** * 查询今日统计 * * @param \Illuminate\Database\Eloquent\Builder $query * @return \Illuminate\Database\Eloquent\Builder */ public function scopeToday($query) { return $query->where('date', now()->toDateString()); } /** * 查询昨日统计 * * @param \Illuminate\Database\Eloquent\Builder $query * @return \Illuminate\Database\Eloquent\Builder */ public function scopeYesterday($query) { return $query->where('date', now()->subDay()->toDateString()); } /** * 查询本周统计 * * @param \Illuminate\Database\Eloquent\Builder $query * @return \Illuminate\Database\Eloquent\Builder */ public function scopeThisWeek($query) { return $query->whereBetween('date', [ now()->startOfWeek()->toDateString(), now()->endOfWeek()->toDateString() ]); } /** * 查询本月统计 * * @param \Illuminate\Database\Eloquent\Builder $query * @return \Illuminate\Database\Eloquent\Builder */ public function scopeThisMonth($query) { return $query->whereBetween('date', [ now()->startOfMonth()->toDateString(), now()->endOfMonth()->toDateString() ]); } }