logger.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. package log
  2. import (
  3. "io"
  4. "log"
  5. "os"
  6. "time"
  7. "v2ray.com/core/common/platform"
  8. "v2ray.com/core/common/signal/done"
  9. "v2ray.com/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() // nolint: errcheck
  43. for {
  44. select {
  45. case <-l.done.Wait():
  46. return
  47. case msg := <-l.buffer:
  48. logger.Write(msg.String() + platform.LineSeparator()) // nolint: errcheck
  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. // CreateFileLogWriter returns a LogWriterCreator that creates LogWriter for the given file.
  102. func CreateFileLogWriter(path string) (WriterCreator, error) {
  103. file, err := os.OpenFile(path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
  104. if err != nil {
  105. return nil, err
  106. }
  107. file.Close()
  108. return func() Writer {
  109. file, err := os.OpenFile(path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
  110. if err != nil {
  111. return nil
  112. }
  113. return &fileLogWriter{
  114. file: file,
  115. logger: log.New(file, "", log.Ldate|log.Ltime),
  116. }
  117. }, nil
  118. }
  119. func init() {
  120. RegisterHandler(NewLogger(CreateStdoutLogWriter()))
  121. }