logger.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  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. // NewLogger returns a generic log handler that can handle all type of messages.
  25. func NewLogger(logWriterCreator WriterCreator) Handler {
  26. return &generalLogger{
  27. creator: logWriterCreator,
  28. buffer: make(chan Message, 16),
  29. access: semaphore.New(1),
  30. done: done.New(),
  31. }
  32. }
  33. func (l *generalLogger) run() {
  34. defer l.access.Signal()
  35. dataWritten := false
  36. ticker := time.NewTicker(time.Minute)
  37. defer ticker.Stop()
  38. logger := l.creator()
  39. if logger == nil {
  40. return
  41. }
  42. defer logger.Close()
  43. for {
  44. select {
  45. case <-l.done.Wait():
  46. return
  47. case msg := <-l.buffer:
  48. logger.Write(msg.String() + platform.LineSeparator())
  49. dataWritten = true
  50. case <-ticker.C:
  51. if !dataWritten {
  52. return
  53. }
  54. dataWritten = false
  55. }
  56. }
  57. }
  58. func (l *generalLogger) Handle(msg Message) {
  59. select {
  60. case l.buffer <- msg:
  61. default:
  62. }
  63. select {
  64. case <-l.access.Wait():
  65. go l.run()
  66. default:
  67. }
  68. }
  69. func (l *generalLogger) Close() error {
  70. return l.done.Close()
  71. }
  72. type consoleLogWriter struct {
  73. logger *log.Logger
  74. }
  75. func (w *consoleLogWriter) Write(s string) error {
  76. w.logger.Print(s)
  77. return nil
  78. }
  79. func (w *consoleLogWriter) Close() error {
  80. return nil
  81. }
  82. type fileLogWriter struct {
  83. file *os.File
  84. logger *log.Logger
  85. }
  86. func (w *fileLogWriter) Write(s string) error {
  87. w.logger.Print(s)
  88. return nil
  89. }
  90. func (w *fileLogWriter) Close() error {
  91. return w.file.Close()
  92. }
  93. // CreateStdoutLogWriter returns a LogWriterCreator that creates LogWriter for stdout.
  94. func CreateStdoutLogWriter() WriterCreator {
  95. return func() Writer {
  96. return &consoleLogWriter{
  97. logger: log.New(os.Stdout, "", log.Ldate|log.Ltime),
  98. }
  99. }
  100. }
  101. // CreateStderrLogWriter returns a LogWriterCreator that creates LogWriter for stderr.
  102. func CreateStderrLogWriter() WriterCreator {
  103. return func() Writer {
  104. return &consoleLogWriter{
  105. logger: log.New(os.Stderr, "", log.Ldate|log.Ltime),
  106. }
  107. }
  108. }
  109. // CreateFileLogWriter returns a LogWriterCreator that creates LogWriter for the given file.
  110. func CreateFileLogWriter(path string) (WriterCreator, error) {
  111. file, err := os.OpenFile(path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0o600)
  112. if err != nil {
  113. return nil, err
  114. }
  115. file.Close()
  116. return func() Writer {
  117. file, err := os.OpenFile(path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0o600)
  118. if err != nil {
  119. return nil
  120. }
  121. return &fileLogWriter{
  122. file: file,
  123. logger: log.New(file, "", log.Ldate|log.Ltime),
  124. }
  125. }, nil
  126. }
  127. func init() {
  128. RegisterHandler(NewLogger(CreateStdoutLogWriter()))
  129. }