github.com/xmplusdev/xray-core@v1.8.10/common/log/logger.go (about) 1 package log 2 3 import ( 4 "io" 5 "log" 6 "os" 7 "time" 8 9 "github.com/xmplusdev/xray-core/common/platform" 10 "github.com/xmplusdev/xray-core/common/signal/done" 11 "github.com/xmplusdev/xray-core/common/signal/semaphore" 12 ) 13 14 // Writer is the interface for writing logs. 15 type Writer interface { 16 Write(string) error 17 io.Closer 18 } 19 20 // WriterCreator is a function to create LogWriters. 21 type WriterCreator func() Writer 22 23 type generalLogger struct { 24 creator WriterCreator 25 buffer chan Message 26 access *semaphore.Instance 27 done *done.Instance 28 } 29 30 type serverityLogger struct { 31 inner *generalLogger 32 logLevel Severity 33 } 34 35 // NewLogger returns a generic log handler that can handle all type of messages. 36 func NewLogger(logWriterCreator WriterCreator) Handler { 37 return &generalLogger{ 38 creator: logWriterCreator, 39 buffer: make(chan Message, 16), 40 access: semaphore.New(1), 41 done: done.New(), 42 } 43 } 44 45 func ReplaceWithSeverityLogger(serverity Severity) { 46 w := CreateStdoutLogWriter() 47 g := &generalLogger{ 48 creator: w, 49 buffer: make(chan Message, 16), 50 access: semaphore.New(1), 51 done: done.New(), 52 } 53 s := &serverityLogger{ 54 inner: g, 55 logLevel: serverity, 56 } 57 RegisterHandler(s) 58 } 59 60 func (l *serverityLogger) Handle(msg Message) { 61 switch msg := msg.(type) { 62 case *GeneralMessage: 63 if msg.Severity <= l.logLevel { 64 l.inner.Handle(msg) 65 } 66 default: 67 l.inner.Handle(msg) 68 } 69 } 70 71 func (l *generalLogger) run() { 72 defer l.access.Signal() 73 74 dataWritten := false 75 ticker := time.NewTicker(time.Minute) 76 defer ticker.Stop() 77 78 logger := l.creator() 79 if logger == nil { 80 return 81 } 82 defer logger.Close() 83 84 for { 85 select { 86 case <-l.done.Wait(): 87 return 88 case msg := <-l.buffer: 89 logger.Write(msg.String() + platform.LineSeparator()) 90 dataWritten = true 91 case <-ticker.C: 92 if !dataWritten { 93 return 94 } 95 dataWritten = false 96 } 97 } 98 } 99 100 func (l *generalLogger) Handle(msg Message) { 101 102 select { 103 case l.buffer <- msg: 104 default: 105 } 106 107 select { 108 case <-l.access.Wait(): 109 go l.run() 110 default: 111 } 112 } 113 114 func (l *generalLogger) Close() error { 115 return l.done.Close() 116 } 117 118 type consoleLogWriter struct { 119 logger *log.Logger 120 } 121 122 func (w *consoleLogWriter) Write(s string) error { 123 w.logger.Print(s) 124 return nil 125 } 126 127 func (w *consoleLogWriter) Close() error { 128 return nil 129 } 130 131 type fileLogWriter struct { 132 file *os.File 133 logger *log.Logger 134 } 135 136 func (w *fileLogWriter) Write(s string) error { 137 w.logger.Print(s) 138 return nil 139 } 140 141 func (w *fileLogWriter) Close() error { 142 return w.file.Close() 143 } 144 145 // CreateStdoutLogWriter returns a LogWriterCreator that creates LogWriter for stdout. 146 func CreateStdoutLogWriter() WriterCreator { 147 return func() Writer { 148 return &consoleLogWriter{ 149 logger: log.New(os.Stdout, "", log.Ldate|log.Ltime), 150 } 151 } 152 } 153 154 // CreateStderrLogWriter returns a LogWriterCreator that creates LogWriter for stderr. 155 func CreateStderrLogWriter() WriterCreator { 156 return func() Writer { 157 return &consoleLogWriter{ 158 logger: log.New(os.Stderr, "", log.Ldate|log.Ltime), 159 } 160 } 161 } 162 163 // CreateFileLogWriter returns a LogWriterCreator that creates LogWriter for the given file. 164 func CreateFileLogWriter(path string) (WriterCreator, error) { 165 file, err := os.OpenFile(path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0o600) 166 if err != nil { 167 return nil, err 168 } 169 file.Close() 170 return func() Writer { 171 file, err := os.OpenFile(path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0o600) 172 if err != nil { 173 return nil 174 } 175 return &fileLogWriter{ 176 file: file, 177 logger: log.New(file, "", log.Ldate|log.Ltime), 178 } 179 }, nil 180 } 181 182 func init() { 183 RegisterHandler(NewLogger(CreateStdoutLogWriter())) 184 }