mirror of
https://github.com/andwati/telecom-platform.git
synced 2026-10-26 22:52:16 +00:00
- Replace map[string]interface{} with map[string]any in UpdateCarrierMetrics
- Replace interface{} with any for GeneratedAt field in PricingEffectiveness struct
- Replace loop-based empty string checks with slices.Contains in ValidateConditions
- Replace range loop index initialization with range-only syntax in calculateAPIPerformance
- Add slices import for standard library slice utilities
211 lines
5.5 KiB
Go
211 lines
5.5 KiB
Go
package services
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
"github.com/nutcas3/telecom-platform/apps/carrier-connector/internal/id"
|
|
"github.com/nutcas3/telecom-platform/apps/carrier-connector/internal/tenant"
|
|
)
|
|
|
|
// parseTimeRange parses time range string and returns start and end dates
|
|
func (s *TenantServiceImpl) parseTimeRange(timeRange string) (time.Time, time.Time) {
|
|
now := time.Now()
|
|
|
|
switch timeRange {
|
|
case "1h":
|
|
return now.Add(-1 * time.Hour), now
|
|
case "24h":
|
|
return now.Add(-24 * time.Hour), now
|
|
case "7d":
|
|
return now.Add(-7 * 24 * time.Hour), now
|
|
case "30d":
|
|
return now.Add(-30 * 24 * time.Hour), now
|
|
case "90d":
|
|
return now.Add(-90 * 24 * time.Hour), now
|
|
default:
|
|
return now.Add(-24 * time.Hour), now
|
|
}
|
|
}
|
|
|
|
// buildQuotaStatus builds quota status from usage stats
|
|
func (s *TenantServiceImpl) buildQuotaStatus(usageStats *tenant.TenantUsageStats) []*tenant.TenantUsage {
|
|
quotaStatus := make([]*tenant.TenantUsage, 0)
|
|
|
|
// Create quota status for common resource types
|
|
resourceTypes := []string{"users", "profiles", "carriers", "api_calls", "storage"}
|
|
|
|
for _, resourceType := range resourceTypes {
|
|
// Get actual usage data from repository
|
|
usage, err := s.repository.GetUsage(context.Background(), usageStats.TenantID, resourceType)
|
|
if err != nil {
|
|
// Create empty usage if not found
|
|
usage = &tenant.TenantUsage{
|
|
ID: id.GenerateUsageID(resourceType, usageStats.TenantID),
|
|
TenantID: usageStats.TenantID,
|
|
ResourceType: resourceType,
|
|
ResourceCount: 0,
|
|
QuotaLimit: 0,
|
|
QuotaUsed: 0,
|
|
QuotaRemaining: 0,
|
|
PeriodStart: time.Now().AddDate(0, -1, 0),
|
|
PeriodEnd: time.Now(),
|
|
}
|
|
}
|
|
|
|
quotaStatus = append(quotaStatus, usage)
|
|
}
|
|
|
|
return quotaStatus
|
|
}
|
|
|
|
// calculateAPIPerformance calculates real API performance metrics
|
|
func (s *TenantServiceImpl) calculateAPIPerformance(requests []*tenant.APIRequestEvent) *tenant.APIPerformance {
|
|
if len(requests) == 0 {
|
|
return &tenant.APIPerformance{
|
|
TotalRequests: 0,
|
|
AverageResponseTime: 0,
|
|
P95ResponseTime: 0,
|
|
ErrorRate: 0,
|
|
RequestsPerSecond: 0,
|
|
}
|
|
}
|
|
|
|
// Calculate performance metrics
|
|
totalRequests := len(requests)
|
|
var totalResponseTime int64
|
|
errorCount := 0
|
|
|
|
responseTimes := make([]int, 0, totalRequests)
|
|
|
|
for _, req := range requests {
|
|
totalResponseTime += int64(req.ResponseTime)
|
|
responseTimes = append(responseTimes, req.ResponseTime)
|
|
|
|
if req.StatusCode >= 400 {
|
|
errorCount++
|
|
}
|
|
}
|
|
|
|
// Calculate average response time
|
|
averageResponseTime := float64(totalResponseTime) / float64(totalRequests)
|
|
|
|
// Calculate P95 response time
|
|
sortedResponseTimes := make([]int, len(responseTimes))
|
|
copy(sortedResponseTimes, responseTimes)
|
|
|
|
// Sort response times
|
|
for i := range sortedResponseTimes {
|
|
for j := 0; j < len(sortedResponseTimes)-1-i; j++ {
|
|
if sortedResponseTimes[j] > sortedResponseTimes[j+1] {
|
|
sortedResponseTimes[j], sortedResponseTimes[j+1] = sortedResponseTimes[j+1], sortedResponseTimes[j]
|
|
}
|
|
}
|
|
}
|
|
|
|
p95Index := int(float64(totalRequests) * 0.95)
|
|
if p95Index >= totalRequests {
|
|
p95Index = totalRequests - 1
|
|
}
|
|
p95ResponseTime := float64(sortedResponseTimes[p95Index])
|
|
|
|
// Calculate error rate
|
|
errorRate := float64(errorCount) / float64(totalRequests) * 100
|
|
|
|
// Calculate requests per second
|
|
requestsPerSecond := float64(totalRequests) / 3600.0
|
|
|
|
return &tenant.APIPerformance{
|
|
TotalRequests: totalRequests,
|
|
AverageResponseTime: averageResponseTime,
|
|
P95ResponseTime: p95ResponseTime,
|
|
ErrorRate: errorRate,
|
|
RequestsPerSecond: requestsPerSecond,
|
|
}
|
|
}
|
|
|
|
// parseAPIRequestEvent parses API request event data
|
|
func (s *TenantServiceImpl) parseAPIRequestEvent(event *tenant.TenantEvent) *tenant.APIRequestEvent {
|
|
endpoint := ""
|
|
method := "GET"
|
|
responseTime := 0
|
|
|
|
// Extract data from event
|
|
if eventData, ok := event.EventData["endpoint"]; ok {
|
|
if ep, ok := eventData.(string); ok {
|
|
endpoint = ep
|
|
}
|
|
}
|
|
|
|
if eventData, ok := event.EventData["method"]; ok {
|
|
if m, ok := eventData.(string); ok {
|
|
method = m
|
|
}
|
|
}
|
|
|
|
if eventData, ok := event.EventData["response_time"]; ok {
|
|
if rt, ok := eventData.(float64); ok {
|
|
responseTime = int(rt)
|
|
}
|
|
}
|
|
|
|
statusCode := 200
|
|
if eventData, ok := event.EventData["status_code"]; ok {
|
|
if sc, ok := eventData.(float64); ok {
|
|
statusCode = int(sc)
|
|
}
|
|
}
|
|
|
|
return &tenant.APIRequestEvent{
|
|
Timestamp: event.Timestamp,
|
|
Endpoint: endpoint,
|
|
Method: method,
|
|
StatusCode: statusCode,
|
|
ResponseTime: responseTime,
|
|
UserID: event.UserID,
|
|
}
|
|
}
|
|
|
|
// parseErrorEvent parses error event data
|
|
func (s *TenantServiceImpl) parseErrorEvent(event *tenant.TenantEvent) *tenant.ErrorEvent {
|
|
errorMsg := ""
|
|
|
|
if eventData, ok := event.EventData["error"]; ok {
|
|
if err, ok := eventData.(string); ok {
|
|
errorMsg = err
|
|
}
|
|
}
|
|
|
|
return &tenant.ErrorEvent{
|
|
Timestamp: event.Timestamp,
|
|
Error: errorMsg,
|
|
Context: event.EventData,
|
|
UserID: event.UserID,
|
|
}
|
|
}
|
|
|
|
// parseSlowQueryEvent parses slow query event data
|
|
func (s *TenantServiceImpl) parseSlowQueryEvent(event *tenant.TenantEvent) *tenant.SlowQuery {
|
|
query := ""
|
|
duration := time.Duration(0)
|
|
|
|
if eventData, ok := event.EventData["query"]; ok {
|
|
if q, ok := eventData.(string); ok {
|
|
query = q
|
|
}
|
|
}
|
|
|
|
if eventData, ok := event.EventData["duration"]; ok {
|
|
if d, ok := eventData.(float64); ok {
|
|
duration = time.Duration(d) * time.Millisecond
|
|
}
|
|
}
|
|
|
|
return &tenant.SlowQuery{
|
|
Timestamp: event.Timestamp,
|
|
Query: query,
|
|
Duration: duration,
|
|
Context: event.EventData,
|
|
}
|
|
}
|