github.com/sagernet/sing-box@v1.9.0-rc.20/log/observable.go (about)

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