nginx_log_index.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. package model
  2. import (
  3. "time"
  4. )
  5. // NginxLogIndex represents the incremental index position and metadata for a log file
  6. type NginxLogIndex struct {
  7. BaseModelUUID
  8. Path string `gorm:"uniqueIndex;size:500;not null" json:"path"` // Log file path
  9. MainLogPath string `gorm:"index;size:500" json:"main_log_path"` // Main log path for grouping related files (access.log for access.log.1, access.log.1.gz, etc.)
  10. LastModified time.Time `json:"last_modified"` // File last modified time when indexed
  11. LastSize int64 `gorm:"default:0" json:"last_size"` // Total index size of all related log files when last indexed
  12. LastPosition int64 `gorm:"default:0" json:"last_position"` // Last byte position indexed in file
  13. LastIndexed time.Time `json:"last_indexed"` // When file was last indexed
  14. IndexStartTime *time.Time `json:"index_start_time"` // When the last indexing operation started
  15. IndexDuration *int64 `json:"index_duration"` // Duration of last indexing operation in milliseconds
  16. TimeRangeStart *time.Time `json:"timerange_start"` // Earliest log entry time
  17. TimeRangeEnd *time.Time `json:"timerange_end"` // Latest log entry time
  18. DocumentCount uint64 `gorm:"default:0" json:"document_count"` // Total documents indexed from this file
  19. Enabled bool `gorm:"default:true" json:"enabled"` // Whether indexing is enabled for this file
  20. HasTimeRange bool `gorm:"-" json:"has_timerange"` // Whether a time range is available (not persisted)
  21. // Extended status fields
  22. IndexStatus string `gorm:"default:'not_indexed';size:50" json:"index_status"` // Current index status
  23. ErrorMessage string `gorm:"type:text" json:"error_message,omitempty"` // Last error message
  24. ErrorTime *time.Time `json:"error_time,omitempty"` // When error occurred
  25. RetryCount int `gorm:"default:0" json:"retry_count"` // Number of retry attempts
  26. QueuePosition int `gorm:"default:0" json:"queue_position,omitempty"` // Position in indexing queue
  27. }
  28. // NeedsIndexing checks if the file needs incremental indexing
  29. func (nli *NginxLogIndex) NeedsIndexing(fileModTime time.Time, fileSize int64) bool {
  30. // If never indexed, needs full indexing
  31. if nli.LastIndexed.IsZero() {
  32. return true
  33. }
  34. // If file was modified after last index and size increased, needs incremental indexing
  35. if fileModTime.After(nli.LastModified) && fileSize > nli.LastSize {
  36. return true
  37. }
  38. // If file size decreased, file might have been rotated, needs full re-indexing
  39. if fileSize < nli.LastSize {
  40. return true
  41. }
  42. return false
  43. }
  44. // ShouldFullReindex checks if a full re-index is needed (file rotation detected)
  45. func (nli *NginxLogIndex) ShouldFullReindex(fileModTime time.Time, fileSize int64) bool {
  46. // File size decreased - likely file rotation
  47. if fileSize < nli.LastSize {
  48. return true
  49. }
  50. // File significantly older than last index - might be a replaced file
  51. if fileModTime.Before(nli.LastModified.Add(-time.Hour)) {
  52. return true
  53. }
  54. return false
  55. }
  56. // UpdateProgress updates the indexing progress
  57. func (nli *NginxLogIndex) UpdateProgress(modTime time.Time, size int64, position int64, docCount uint64, timeStart, timeEnd *time.Time) {
  58. nli.LastModified = modTime
  59. nli.LastSize = size
  60. nli.LastPosition = position
  61. nli.LastIndexed = time.Now()
  62. nli.DocumentCount = docCount
  63. // Merge time ranges: preserve existing historical range and expand if necessary
  64. // This prevents incremental updates from losing historical time range data
  65. if timeStart != nil {
  66. if nli.TimeRangeStart == nil || timeStart.Before(*nli.TimeRangeStart) {
  67. nli.TimeRangeStart = timeStart
  68. }
  69. }
  70. if timeEnd != nil {
  71. if nli.TimeRangeEnd == nil || timeEnd.After(*nli.TimeRangeEnd) {
  72. nli.TimeRangeEnd = timeEnd
  73. }
  74. }
  75. }
  76. // SetIndexStartTime records when indexing operation started
  77. func (nli *NginxLogIndex) SetIndexStartTime(startTime time.Time) {
  78. nli.IndexStartTime = &startTime
  79. }
  80. // SetIndexDuration records how long the indexing operation took
  81. func (nli *NginxLogIndex) SetIndexDuration(startTime time.Time) {
  82. // If IndexStartTime is not set, set it to the provided startTime
  83. if nli.IndexStartTime == nil {
  84. nli.IndexStartTime = &startTime
  85. }
  86. duration := time.Since(startTime).Milliseconds()
  87. nli.IndexDuration = &duration
  88. }
  89. // Reset clears all index position data for full re-indexing
  90. func (nli *NginxLogIndex) Reset() {
  91. nli.LastModified = time.Time{} // Clear last modified time
  92. nli.LastSize = 0 // Clear index size
  93. nli.LastPosition = 0
  94. nli.LastIndexed = time.Time{} // Clear last indexed time
  95. nli.IndexStartTime = nil // Clear index start time
  96. nli.IndexDuration = nil // Clear index duration
  97. nli.DocumentCount = 0
  98. nli.TimeRangeStart = nil
  99. nli.TimeRangeEnd = nil
  100. // Reset status fields
  101. nli.IndexStatus = "not_indexed"
  102. nli.ErrorMessage = ""
  103. nli.ErrorTime = nil
  104. nli.RetryCount = 0
  105. nli.QueuePosition = 0
  106. }
  107. // SetIndexingStatus updates the indexing status
  108. func (nli *NginxLogIndex) SetIndexingStatus(status string) {
  109. nli.IndexStatus = status
  110. if status == "indexing" {
  111. now := time.Now()
  112. nli.IndexStartTime = &now
  113. }
  114. }
  115. // SetErrorStatus records an error status with message
  116. func (nli *NginxLogIndex) SetErrorStatus(errorMessage string) {
  117. nli.IndexStatus = "error"
  118. nli.ErrorMessage = errorMessage
  119. now := time.Now()
  120. nli.ErrorTime = &now
  121. nli.RetryCount++
  122. }
  123. // SetCompletedStatus marks indexing as completed successfully
  124. func (nli *NginxLogIndex) SetCompletedStatus() {
  125. nli.IndexStatus = "indexed"
  126. nli.ErrorMessage = ""
  127. nli.ErrorTime = nil
  128. nli.QueuePosition = 0
  129. }
  130. // SetQueuedStatus marks the file as queued for indexing
  131. func (nli *NginxLogIndex) SetQueuedStatus(position int) {
  132. nli.IndexStatus = "queued"
  133. nli.QueuePosition = position
  134. }
  135. // IsHealthy returns true if the index is in a good state
  136. func (nli *NginxLogIndex) IsHealthy() bool {
  137. return nli.IndexStatus == "indexed" || nli.IndexStatus == "indexing"
  138. }
  139. // CanRetry returns true if the file can be retried for indexing
  140. func (nli *NginxLogIndex) CanRetry() bool {
  141. return nli.IndexStatus == "error"
  142. }