1
0

logger.go 3.5 KB

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