observable.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. package log
  2. import (
  3. "context"
  4. "io"
  5. "os"
  6. "time"
  7. "github.com/sagernet/sing/common"
  8. F "github.com/sagernet/sing/common/format"
  9. "github.com/sagernet/sing/common/observable"
  10. "github.com/sagernet/sing/service/filemanager"
  11. )
  12. var _ Factory = (*defaultFactory)(nil)
  13. type defaultFactory struct {
  14. ctx context.Context
  15. formatter Formatter
  16. platformFormatter Formatter
  17. writer io.Writer
  18. file *os.File
  19. filePath string
  20. platformWriter PlatformWriter
  21. needObservable bool
  22. level Level
  23. subscriber *observable.Subscriber[Entry]
  24. observer *observable.Observer[Entry]
  25. }
  26. func NewDefaultFactory(
  27. ctx context.Context,
  28. formatter Formatter,
  29. writer io.Writer,
  30. filePath string,
  31. platformWriter PlatformWriter,
  32. needObservable bool,
  33. ) ObservableFactory {
  34. factory := &defaultFactory{
  35. ctx: ctx,
  36. formatter: formatter,
  37. platformFormatter: Formatter{
  38. BaseTime: formatter.BaseTime,
  39. DisableLineBreak: true,
  40. },
  41. writer: writer,
  42. filePath: filePath,
  43. platformWriter: platformWriter,
  44. needObservable: needObservable,
  45. level: LevelTrace,
  46. subscriber: observable.NewSubscriber[Entry](128),
  47. }
  48. if platformWriter != nil {
  49. factory.platformFormatter.DisableColors = platformWriter.DisableColors()
  50. }
  51. if needObservable {
  52. factory.observer = observable.NewObserver[Entry](factory.subscriber, 64)
  53. }
  54. return factory
  55. }
  56. func (f *defaultFactory) Start() error {
  57. if f.filePath != "" {
  58. logFile, err := filemanager.OpenFile(f.ctx, f.filePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644)
  59. if err != nil {
  60. return err
  61. }
  62. f.writer = logFile
  63. f.file = logFile
  64. }
  65. return nil
  66. }
  67. func (f *defaultFactory) Close() error {
  68. return common.Close(
  69. common.PtrOrNil(f.file),
  70. f.subscriber,
  71. )
  72. }
  73. func (f *defaultFactory) Level() Level {
  74. return f.level
  75. }
  76. func (f *defaultFactory) SetLevel(level Level) {
  77. f.level = level
  78. }
  79. func (f *defaultFactory) Logger() ContextLogger {
  80. return f.NewLogger("")
  81. }
  82. func (f *defaultFactory) NewLogger(tag string) ContextLogger {
  83. return &observableLogger{f, tag}
  84. }
  85. func (f *defaultFactory) Subscribe() (subscription observable.Subscription[Entry], done <-chan struct{}, err error) {
  86. return f.observer.Subscribe()
  87. }
  88. func (f *defaultFactory) UnSubscribe(sub observable.Subscription[Entry]) {
  89. f.observer.UnSubscribe(sub)
  90. }
  91. var _ ContextLogger = (*observableLogger)(nil)
  92. type observableLogger struct {
  93. *defaultFactory
  94. tag string
  95. }
  96. func (l *observableLogger) Log(ctx context.Context, level Level, args []any) {
  97. level = OverrideLevelFromContext(level, ctx)
  98. if level > l.level {
  99. return
  100. }
  101. nowTime := time.Now()
  102. if l.needObservable {
  103. message, messageSimple := l.formatter.FormatWithSimple(ctx, level, l.tag, F.ToString(args...), nowTime)
  104. if level == LevelPanic {
  105. panic(message)
  106. }
  107. l.writer.Write([]byte(message))
  108. if level == LevelFatal {
  109. os.Exit(1)
  110. }
  111. l.subscriber.Emit(Entry{level, messageSimple})
  112. } else {
  113. message := l.formatter.Format(ctx, level, l.tag, F.ToString(args...), nowTime)
  114. if level == LevelPanic {
  115. panic(message)
  116. }
  117. l.writer.Write([]byte(message))
  118. if level == LevelFatal {
  119. os.Exit(1)
  120. }
  121. }
  122. if l.platformWriter != nil {
  123. l.platformWriter.WriteMessage(level, l.platformFormatter.Format(ctx, level, l.tag, F.ToString(args...), nowTime))
  124. }
  125. }
  126. func (l *observableLogger) Trace(args ...any) {
  127. l.TraceContext(context.Background(), args...)
  128. }
  129. func (l *observableLogger) Debug(args ...any) {
  130. l.DebugContext(context.Background(), args...)
  131. }
  132. func (l *observableLogger) Info(args ...any) {
  133. l.InfoContext(context.Background(), args...)
  134. }
  135. func (l *observableLogger) Warn(args ...any) {
  136. l.WarnContext(context.Background(), args...)
  137. }
  138. func (l *observableLogger) Error(args ...any) {
  139. l.ErrorContext(context.Background(), args...)
  140. }
  141. func (l *observableLogger) Fatal(args ...any) {
  142. l.FatalContext(context.Background(), args...)
  143. }
  144. func (l *observableLogger) Panic(args ...any) {
  145. l.PanicContext(context.Background(), args...)
  146. }
  147. func (l *observableLogger) TraceContext(ctx context.Context, args ...any) {
  148. l.Log(ctx, LevelTrace, args)
  149. }
  150. func (l *observableLogger) DebugContext(ctx context.Context, args ...any) {
  151. l.Log(ctx, LevelDebug, args)
  152. }
  153. func (l *observableLogger) InfoContext(ctx context.Context, args ...any) {
  154. l.Log(ctx, LevelInfo, args)
  155. }
  156. func (l *observableLogger) WarnContext(ctx context.Context, args ...any) {
  157. l.Log(ctx, LevelWarn, args)
  158. }
  159. func (l *observableLogger) ErrorContext(ctx context.Context, args ...any) {
  160. l.Log(ctx, LevelError, args)
  161. }
  162. func (l *observableLogger) FatalContext(ctx context.Context, args ...any) {
  163. l.Log(ctx, LevelFatal, args)
  164. }
  165. func (l *observableLogger) PanicContext(ctx context.Context, args ...any) {
  166. l.Log(ctx, LevelPanic, args)
  167. }