diff --git a/internal/xray/api.go b/internal/xray/api.go index ea417e4e2..bbcb63ed1 100644 --- a/internal/xray/api.go +++ b/internal/xray/api.go @@ -38,6 +38,13 @@ import ( "google.golang.org/grpc/status" ) +// Compiled once at package load: GetTraffic runs on every traffic-stats tick, +// so recompiling these per call is wasted work. +var ( + trafficRegex = regexp.MustCompile(`(inbound|outbound)>>>([^>]+)>>>traffic>>>(downlink|uplink)`) + clientTrafficRegex = regexp.MustCompile(`user>>>([^>]+)>>>traffic>>>(downlink|uplink)`) +) + // XrayAPI is a gRPC client for managing Xray core configuration, inbounds, outbounds, and statistics. type XrayAPI struct { HandlerServiceClient *command.HandlerServiceClient @@ -537,9 +544,6 @@ func (x *XrayAPI) GetTraffic() ([]*Traffic, []*ClientTraffic, error) { return nil, nil, common.NewError("xray api is not initialized") } - trafficRegex := regexp.MustCompile(`(inbound|outbound)>>>([^>]+)>>>traffic>>>(downlink|uplink)`) - clientTrafficRegex := regexp.MustCompile(`user>>>([^>]+)>>>traffic>>>(downlink|uplink)`) - ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) defer cancel() diff --git a/internal/xray/log_writer.go b/internal/xray/log_writer.go index 4004a1e56..2e8c2d091 100644 --- a/internal/xray/log_writer.go +++ b/internal/xray/log_writer.go @@ -8,6 +8,13 @@ import ( "github.com/mhsanaei/3x-ui/v3/internal/logger" ) +// Compiled once at package load: Write runs on every line Xray emits, so +// recompiling these per write is wasted work. +var ( + crashRegex = regexp.MustCompile(`(?i)(panic|exception|stack trace|fatal error)`) + logLineRegex = regexp.MustCompile(`^(\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2}\.\d{6}) \[([^\]]+)\] (.+)$`) +) + // NewLogWriter returns a new LogWriter for processing Xray log output. func NewLogWriter() *LogWriter { return &LogWriter{} @@ -20,8 +27,6 @@ type LogWriter struct { // Write processes and filters log output from the Xray process, handling crash detection and message filtering. func (lw *LogWriter) Write(m []byte) (n int, err error) { - crashRegex := regexp.MustCompile(`(?i)(panic|exception|stack trace|fatal error)`) - // Convert the data to a string message := strings.TrimSpace(string(m)) msgLowerAll := strings.ToLower(message) @@ -42,11 +47,10 @@ func (lw *LogWriter) Write(m []byte) (n int, err error) { return len(m), nil } - regex := regexp.MustCompile(`^(\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2}\.\d{6}) \[([^\]]+)\] (.+)$`) messages := strings.SplitSeq(message, "\n") for msg := range messages { - matches := regex.FindStringSubmatch(msg) + matches := logLineRegex.FindStringSubmatch(msg) if len(matches) > 3 { level := matches[2]