clear_logs_job.go 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. package job
  2. import (
  3. "io"
  4. "os"
  5. "path/filepath"
  6. "github.com/mhsanaei/3x-ui/v3/internal/logger"
  7. "github.com/mhsanaei/3x-ui/v3/internal/xray"
  8. )
  9. // ClearLogsJob clears old log files to prevent disk space issues.
  10. type ClearLogsJob struct{}
  11. // NewClearLogsJob creates a new log cleanup job instance.
  12. func NewClearLogsJob() *ClearLogsJob {
  13. return new(ClearLogsJob)
  14. }
  15. // ensureFileExists creates the necessary directories and file if they don't exist
  16. func ensureFileExists(path string) error {
  17. dir := filepath.Dir(path)
  18. if err := os.MkdirAll(dir, 0755); err != nil {
  19. return err
  20. }
  21. file, err := os.OpenFile(path, os.O_CREATE|os.O_RDWR, 0644)
  22. if err != nil {
  23. return err
  24. }
  25. file.Close()
  26. return nil
  27. }
  28. // Here Run is an interface method of the Job interface
  29. func (j *ClearLogsJob) Run() {
  30. logFiles := []string{xray.GetIPLimitLogPath(), xray.GetIPLimitBannedLogPath()}
  31. logFilesPrev := []string{xray.GetIPLimitBannedPrevLogPath()}
  32. // Ensure all log files and their paths exist
  33. for _, path := range append(logFiles, logFilesPrev...) {
  34. if err := ensureFileExists(path); err != nil {
  35. logger.Warning("Failed to ensure log file exists:", path, "-", err)
  36. }
  37. }
  38. // Clear log files and copy to previous logs
  39. for i := range len(logFiles) {
  40. if i > 0 {
  41. // Copy to previous logs
  42. logFilePrev, err := os.OpenFile(logFilesPrev[i-1], os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
  43. if err != nil {
  44. logger.Warning("Failed to open previous log file for writing:", logFilesPrev[i-1], "-", err)
  45. continue
  46. }
  47. logFile, err := os.OpenFile(logFiles[i], os.O_RDONLY, 0644)
  48. if err != nil {
  49. logger.Warning("Failed to open current log file for reading:", logFiles[i], "-", err)
  50. logFilePrev.Close()
  51. continue
  52. }
  53. _, err = io.Copy(logFilePrev, logFile)
  54. if err != nil {
  55. logger.Warning("Failed to copy log file:", logFiles[i], "to", logFilesPrev[i-1], "-", err)
  56. }
  57. logFile.Close()
  58. logFilePrev.Close()
  59. }
  60. err := os.Truncate(logFiles[i], 0)
  61. if err != nil {
  62. logger.Warning("Failed to truncate log file:", logFiles[i], "-", err)
  63. }
  64. }
  65. wipeAccessLog()
  66. }
  67. // wipeAccessLog truncates the user-configured Xray access log so it can't grow
  68. // unbounded. The IP-limit job no longer reads or rotates it, so this daily wipe
  69. // is the only thing that caps it. A disabled ("none") or unset access log is
  70. // left alone, and a missing file is fine — there's nothing to wipe.
  71. func wipeAccessLog() {
  72. accessLogPath, err := xray.GetAccessLogPath()
  73. if err != nil || accessLogPath == "none" || accessLogPath == "" {
  74. return
  75. }
  76. if err := os.Truncate(accessLogPath, 0); err != nil && !os.IsNotExist(err) {
  77. logger.Warning("Failed to truncate access log:", accessLogPath, "-", err)
  78. }
  79. }