analytics_service_dashboard.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. package nginx_log
  2. import (
  3. "context"
  4. "fmt"
  5. "github.com/uozi-tech/cosy/logger"
  6. )
  7. // GetDashboardAnalytics generates comprehensive dashboard analytics
  8. func (s *AnalyticsService) GetDashboardAnalytics(ctx context.Context, req *DashboardQueryRequest) (*DashboardAnalytics, error) {
  9. if s.indexer == nil {
  10. return nil, fmt.Errorf("log indexer not available")
  11. }
  12. // Build comprehensive search request to get all entries in the time range
  13. searchReq := &QueryRequest{
  14. StartTime: req.StartTime,
  15. EndTime: req.EndTime,
  16. LogPath: req.LogPath,
  17. Limit: 0, // No limit - get all entries
  18. Offset: 0,
  19. SortBy: "timestamp",
  20. SortOrder: "asc",
  21. }
  22. // Execute search to get all log entries
  23. result, err := s.indexer.SearchLogs(ctx, searchReq)
  24. if err != nil {
  25. return nil, fmt.Errorf("failed to search logs: %w", err)
  26. }
  27. // Calculate dashboard analytics - ensure we initialize with empty arrays using make
  28. analytics := &DashboardAnalytics{
  29. HourlyStats: make([]HourlyAccessStats, 0),
  30. DailyStats: make([]DailyAccessStats, 0),
  31. TopURLs: make([]URLAccessStats, 0),
  32. Browsers: make([]BrowserAccessStats, 0),
  33. OperatingSystems: make([]OSAccessStats, 0),
  34. Devices: make([]DeviceAccessStats, 0),
  35. }
  36. // Only calculate if we have entries
  37. if len(result.Entries) > 0 {
  38. analytics.HourlyStats = s.calculateHourlyStats(result.Entries, req.StartTime, req.EndTime)
  39. analytics.DailyStats = s.calculateDailyStats(result.Entries, req.StartTime, req.EndTime)
  40. analytics.TopURLs = s.calculateTopURLs(result.Entries)
  41. analytics.Browsers = s.calculateBrowserStats(result.Entries)
  42. analytics.OperatingSystems = s.calculateOSStats(result.Entries)
  43. analytics.Devices = s.calculateDeviceStats(result.Entries)
  44. }
  45. // Calculate summary statistics
  46. analytics.Summary = s.calculateDashboardSummary(analytics, result.Entries)
  47. return analytics, nil
  48. }
  49. // GetDashboardAnalyticsFromStats retrieves dashboard analytics using Bleve aggregations
  50. func (s *AnalyticsService) GetDashboardAnalyticsFromStats(ctx context.Context, req *DashboardQueryRequest) (*DashboardAnalytics, error) {
  51. // Use Bleve stats service instead of database statistics
  52. bleveStatsService := GetBleveStatsService()
  53. if bleveStatsService == nil {
  54. return nil, fmt.Errorf("Bleve stats service not available")
  55. }
  56. logger.Infof("Using Bleve-based statistics for log path: %s", req.LogPath)
  57. // Get analytics from Bleve index
  58. analytics, err := bleveStatsService.GetDashboardAnalytics(ctx, req)
  59. if err != nil {
  60. return nil, fmt.Errorf("failed to get dashboard analytics from Bleve: %w", err)
  61. }
  62. logger.Debugf("Successfully retrieved dashboard analytics from Bleve")
  63. return analytics, nil
  64. }
  65. // calculateDashboardSummary calculates summary statistics for the dashboard
  66. func (s *AnalyticsService) calculateDashboardSummary(analytics *DashboardAnalytics, entries []*AccessLogEntry) DashboardSummary {
  67. // Calculate total UV and PV
  68. uniqueIPs := make(map[string]bool)
  69. for _, entry := range entries {
  70. uniqueIPs[entry.IP] = true
  71. }
  72. totalUV := len(uniqueIPs)
  73. totalPV := len(entries)
  74. // Calculate average daily UV and PV
  75. var avgDailyUV, avgDailyPV float64
  76. if len(analytics.DailyStats) > 0 {
  77. totalDays := len(analytics.DailyStats)
  78. var sumUV, sumPV int
  79. for _, daily := range analytics.DailyStats {
  80. sumUV += daily.UV
  81. sumPV += daily.PV
  82. }
  83. avgDailyUV = float64(sumUV) / float64(totalDays)
  84. avgDailyPV = float64(sumPV) / float64(totalDays)
  85. }
  86. // Find peak hour
  87. var peakHour, peakHourTraffic int
  88. for _, hourly := range analytics.HourlyStats {
  89. if hourly.PV > peakHourTraffic {
  90. peakHour = hourly.Hour
  91. peakHourTraffic = hourly.PV
  92. }
  93. }
  94. return DashboardSummary{
  95. TotalUV: totalUV,
  96. TotalPV: totalPV,
  97. AvgDailyUV: avgDailyUV,
  98. AvgDailyPV: avgDailyPV,
  99. PeakHour: peakHour,
  100. PeakHourTraffic: peakHourTraffic,
  101. }
  102. }