analytics_service_entries.go 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. package nginx_log
  2. import (
  3. "context"
  4. "fmt"
  5. "time"
  6. "github.com/uozi-tech/cosy/logger"
  7. )
  8. // GetLogEntries retrieves log entries from a file
  9. func (s *AnalyticsService) GetLogEntries(logPath string, limit int, tail bool) ([]*AccessLogEntry, error) {
  10. if logPath == "" {
  11. return nil, fmt.Errorf("log path is required")
  12. }
  13. // Validate log path
  14. if err := s.ValidateLogPath(logPath); err != nil {
  15. return nil, err
  16. }
  17. // Handle limit: 0 means no limit, negative values get default limit
  18. if limit < 0 {
  19. limit = 100
  20. }
  21. // Enforce maximum limit only if limit is not 0 (unlimited)
  22. if limit > 1000 && limit != 0 {
  23. limit = 1000
  24. }
  25. // Use indexer if available for better performance
  26. if s.indexer != nil {
  27. ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
  28. defer cancel()
  29. queryReq := &QueryRequest{
  30. Limit: limit,
  31. Offset: 0,
  32. }
  33. result, err := s.indexer.SearchLogs(ctx, queryReq)
  34. if err == nil && len(result.Entries) > 0 {
  35. return result.Entries, nil
  36. }
  37. // Fall back to direct file reading if indexer fails
  38. }
  39. // Direct file parsing as fallback
  40. entries, err := s.parseLogFileDirectly(logPath, limit, tail)
  41. if err != nil {
  42. return nil, fmt.Errorf("failed to parse log file: %w", err)
  43. }
  44. return entries, nil
  45. }
  46. // parseLogFileDirectly parses log file directly without indexer
  47. func (s *AnalyticsService) parseLogFileDirectly(logPath string, limit int, tail bool) ([]*AccessLogEntry, error) {
  48. // This is a simplified implementation
  49. // In a real scenario, you might want to implement proper file reading with tail support
  50. return []*AccessLogEntry{}, nil
  51. }
  52. // GetIndexStatus returns comprehensive status and statistics about the indexer
  53. func (s *AnalyticsService) GetIndexStatus() (*IndexStatus, error) {
  54. if s.indexer == nil {
  55. return nil, ErrIndexerNotAvailable
  56. }
  57. return s.indexer.GetIndexStatus()
  58. }
  59. // GetPreflightStatus returns the preflight status for log indexing
  60. func (s *AnalyticsService) GetPreflightStatus(logPath string) (*PreflightResult, error) {
  61. var start, end time.Time
  62. var indexStatus string
  63. logger.Infof("GetPreflightStatus called with logPath='%s'", logPath)
  64. // Check if analytics service has an indexer
  65. if s.indexer == nil {
  66. logger.Error("GetPreflightStatus: Analytics service has no indexer")
  67. return &PreflightResult{
  68. StartTime: 0,
  69. EndTime: 0,
  70. Available: false,
  71. IndexStatus: IndexStatusNotIndexed,
  72. }, nil
  73. }
  74. logger.Infof("GetPreflightStatus: Analytics service has indexer")
  75. // Check real indexing status using IndexingStatusManager
  76. statusManager := GetIndexingStatusManager()
  77. isCurrentlyIndexing := statusManager.IsIndexing()
  78. logger.Infof("GetPreflightStatus: Is currently indexing: %v", isCurrentlyIndexing)
  79. if logPath != "" {
  80. // Validate log path exists
  81. if err := s.ValidateLogPath(logPath); err != nil {
  82. return nil, err
  83. }
  84. // Get time range from Bleve for specific log file
  85. start, end = s.GetTimeRangeFromSummaryStatsForPath(logPath)
  86. // Debug: Log the time range results
  87. logger.Debugf("File %s - start=%v, end=%v, start.IsZero()=%v, end.IsZero()=%v",
  88. logPath, start, end, start.IsZero(), end.IsZero())
  89. // Check if this specific file is being indexed
  90. isFileIndexing := IsFileIndexing(logPath)
  91. logger.Debugf("File %s - IsFileIndexing=%v", logPath, isFileIndexing)
  92. if isFileIndexing {
  93. indexStatus = IndexStatusIndexing
  94. logger.Debugf("File %s is currently being indexed", logPath)
  95. } else if !start.IsZero() && !end.IsZero() {
  96. // File has been indexed and has data available in Bleve
  97. indexStatus = IndexStatusReady
  98. logger.Debugf("File %s is ready with data from %v to %v", logPath, start, end)
  99. } else {
  100. // Fallback: Check if file is actually indexed by querying index status
  101. logger.Debugf("Attempting fallback index status check for %s", logPath)
  102. indexStatusResult, err := s.GetIndexStatus()
  103. if err != nil {
  104. logger.Debugf("GetIndexStatus failed: %v", err)
  105. } else if indexStatusResult == nil {
  106. logger.Debugf("GetIndexStatus returned nil")
  107. } else {
  108. logger.Debugf("GetIndexStatus returned %d files", len(indexStatusResult.Files))
  109. // Look for this file in the index status
  110. found := false
  111. for _, file := range indexStatusResult.Files {
  112. if file.Path == logPath {
  113. found = true
  114. logger.Debugf("Found matching path %s, HasTimeRange=%v", logPath, file.HasTimeRange)
  115. if file.HasTimeRange && file.TimeRangeStart != 0 && file.TimeRangeEnd != 0 {
  116. // File is indexed with time range data
  117. start = time.Unix(file.TimeRangeStart, 0)
  118. end = time.Unix(file.TimeRangeEnd, 0)
  119. indexStatus = IndexStatusReady
  120. logger.Debugf("File %s found in index status with time range %v to %v", logPath, start, end)
  121. goto statusDetermined
  122. }
  123. }
  124. }
  125. if !found {
  126. logger.Debugf("File %s not found in index status", logPath)
  127. }
  128. }
  129. // File exists but either hasn't been indexed yet or has no data
  130. indexStatus = IndexStatusNotIndexed
  131. logger.Debugf("File %s has not been indexed or has no time range data", logPath)
  132. }
  133. statusDetermined:
  134. } else {
  135. // No log path available (default path not found)
  136. if isCurrentlyIndexing {
  137. indexStatus = IndexStatusIndexing
  138. logger.Debug("No specific log path, but indexing is currently in progress")
  139. } else {
  140. indexStatus = IndexStatusNotIndexed
  141. logger.Debug("No log path available and no indexing in progress")
  142. }
  143. }
  144. var startUnix, endUnix int64
  145. if !start.IsZero() {
  146. startUnix = start.Unix()
  147. }
  148. if !end.IsZero() {
  149. endUnix = end.Unix()
  150. }
  151. // Data is available if we have time range data from Bleve or if currently indexing
  152. dataAvailable := (!start.IsZero() && !end.IsZero()) || indexStatus == IndexStatusIndexing
  153. result := &PreflightResult{
  154. StartTime: startUnix,
  155. EndTime: endUnix,
  156. Available: dataAvailable,
  157. IndexStatus: indexStatus,
  158. }
  159. logger.Debugf("Preflight result: log_path=%s, available=%v, index_status=%s",
  160. logPath, dataAvailable, indexStatus)
  161. return result, nil
  162. }