nginx_log.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. package nginx_log
  2. import (
  3. "path/filepath"
  4. "regexp"
  5. "strings"
  6. "github.com/0xJacky/Nginx-UI/internal/cache"
  7. "github.com/0xJacky/Nginx-UI/internal/nginx"
  8. "github.com/0xJacky/Nginx-UI/internal/nginx_log/utlis"
  9. )
  10. // Regular expression for log directives - matches access_log or error_log
  11. var (
  12. logDirectiveRegex = regexp.MustCompile(`(?m)(access_log|error_log)\s+([^\s;]+)(?:\s+[^;]+)?;`)
  13. )
  14. // Use init function to automatically register callback
  15. func init() {
  16. // Register the callback directly with the global registry
  17. cache.RegisterCallback(scanForLogDirectives)
  18. }
  19. // scanForLogDirectives scans and parses configuration files for log directives
  20. func scanForLogDirectives(configPath string, content []byte) error {
  21. prefix := nginx.GetPrefix()
  22. // First, remove all log paths that came from this config file
  23. // This ensures that removed log directives are properly cleaned up
  24. RemoveLogPathsFromConfig(configPath)
  25. // Find log directives using regex
  26. matches := logDirectiveRegex.FindAllSubmatch(content, -1)
  27. // Parse log paths
  28. for _, match := range matches {
  29. if len(match) >= 3 {
  30. // Check if this match is from a commented line
  31. if isCommentedMatch(content, match) {
  32. continue // Skip commented directives
  33. }
  34. directiveType := string(match[1]) // "access_log" or "error_log"
  35. logPath := string(match[2]) // Path to log file
  36. // Skip if log is disabled with "off"
  37. if logPath == "off" {
  38. continue
  39. }
  40. // Handle relative paths by joining with nginx prefix
  41. if !filepath.IsAbs(logPath) {
  42. logPath = filepath.Join(prefix, logPath)
  43. }
  44. // Validate log path
  45. if utlis.IsValidLogPath(logPath) {
  46. logType := "access"
  47. if directiveType == "error_log" {
  48. logType = "error"
  49. }
  50. // Add to cache with config file path
  51. AddLogPath(logPath, logType, filepath.Base(logPath), configPath)
  52. }
  53. }
  54. }
  55. return nil
  56. }
  57. // isCommentedMatch checks if a regex match is from a commented line
  58. func isCommentedMatch(content []byte, match [][]byte) bool {
  59. // Find the position of the match in the content
  60. matchStr := string(match[0])
  61. matchIndex := strings.Index(string(content), matchStr)
  62. if matchIndex == -1 {
  63. return false
  64. }
  65. // Find the start of the line containing this match
  66. lineStart := matchIndex
  67. for lineStart > 0 && content[lineStart-1] != '\n' {
  68. lineStart--
  69. }
  70. // Check if the line starts with # (possibly with leading whitespace)
  71. for i := lineStart; i < matchIndex; i++ {
  72. char := content[i]
  73. if char == '#' {
  74. return true // This is a commented line
  75. }
  76. if char != ' ' && char != '\t' {
  77. return false // Found non-whitespace before the directive, not a comment
  78. }
  79. }
  80. return false
  81. }
  82. // GetAllLogs returns all log paths
  83. func GetAllLogs(filters ...func(*NginxLogCache) bool) []*NginxLogCache {
  84. return GetAllLogPaths(filters...)
  85. }