log_writer.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. package xray
  2. import (
  3. "regexp"
  4. "runtime"
  5. "strings"
  6. "github.com/mhsanaei/3x-ui/v2/logger"
  7. )
  8. // NewLogWriter returns a new LogWriter for processing Xray log output.
  9. func NewLogWriter() *LogWriter {
  10. return &LogWriter{}
  11. }
  12. // LogWriter processes and filters log output from the Xray process, handling crash detection and message filtering.
  13. type LogWriter struct {
  14. lastLine string
  15. }
  16. // Write processes and filters log output from the Xray process, handling crash detection and message filtering.
  17. func (lw *LogWriter) Write(m []byte) (n int, err error) {
  18. crashRegex := regexp.MustCompile(`(?i)(panic|exception|stack trace|fatal error)`)
  19. // Convert the data to a string
  20. message := strings.TrimSpace(string(m))
  21. msgLowerAll := strings.ToLower(message)
  22. // Suppress noisy Windows process-kill signal that surfaces as exit status 1
  23. if runtime.GOOS == "windows" && strings.Contains(msgLowerAll, "exit status 1") {
  24. return len(m), nil
  25. }
  26. // Check if the message contains a crash
  27. if crashRegex.MatchString(message) {
  28. logger.Debug("Core crash detected:\n", message)
  29. lw.lastLine = message
  30. err1 := writeCrashReport(m)
  31. if err1 != nil {
  32. logger.Error("Unable to write crash report:", err1)
  33. }
  34. return len(m), nil
  35. }
  36. regex := regexp.MustCompile(`^(\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2}\.\d{6}) \[([^\]]+)\] (.+)$`)
  37. messages := strings.SplitSeq(message, "\n")
  38. for msg := range messages {
  39. matches := regex.FindStringSubmatch(msg)
  40. if len(matches) > 3 {
  41. level := matches[2]
  42. msgBody := matches[3]
  43. msgBodyLower := strings.ToLower(msgBody)
  44. if strings.Contains(msgBodyLower, "tls handshake error") ||
  45. strings.Contains(msgBodyLower, "connection ends") {
  46. logger.Debug("XRAY: " + msgBody)
  47. lw.lastLine = ""
  48. continue
  49. }
  50. if strings.Contains(msgBodyLower, "failed") {
  51. logger.Error("XRAY: " + msgBody)
  52. } else {
  53. switch level {
  54. case "Debug":
  55. logger.Debug("XRAY: " + msgBody)
  56. case "Info":
  57. logger.Info("XRAY: " + msgBody)
  58. case "Warning":
  59. logger.Warning("XRAY: " + msgBody)
  60. case "Error":
  61. logger.Error("XRAY: " + msgBody)
  62. default:
  63. logger.Debug("XRAY: " + msg)
  64. }
  65. }
  66. lw.lastLine = ""
  67. } else if msg != "" {
  68. msgLower := strings.ToLower(msg)
  69. if strings.Contains(msgLower, "tls handshake error") ||
  70. strings.Contains(msgLower, "connection ends") {
  71. logger.Debug("XRAY: " + msg)
  72. lw.lastLine = msg
  73. continue
  74. }
  75. if strings.Contains(msgLower, "failed") {
  76. logger.Error("XRAY: " + msg)
  77. } else {
  78. logger.Debug("XRAY: " + msg)
  79. }
  80. lw.lastLine = msg
  81. }
  82. }
  83. return len(m), nil
  84. }