123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184 |
- package log
- import (
- "io"
- "log"
- "os"
- "time"
- "github.com/xtls/xray-core/common/platform"
- "github.com/xtls/xray-core/common/signal/done"
- "github.com/xtls/xray-core/common/signal/semaphore"
- )
- // Writer is the interface for writing logs.
- type Writer interface {
- Write(string) error
- io.Closer
- }
- // WriterCreator is a function to create LogWriters.
- type WriterCreator func() Writer
- type generalLogger struct {
- creator WriterCreator
- buffer chan Message
- access *semaphore.Instance
- done *done.Instance
- }
- type serverityLogger struct {
- inner *generalLogger
- logLevel Severity
- }
- // NewLogger returns a generic log handler that can handle all type of messages.
- func NewLogger(logWriterCreator WriterCreator) Handler {
- return &generalLogger{
- creator: logWriterCreator,
- buffer: make(chan Message, 16),
- access: semaphore.New(1),
- done: done.New(),
- }
- }
- func ReplaceWithSeverityLogger(serverity Severity) {
- w := CreateStdoutLogWriter()
- g := &generalLogger{
- creator: w,
- buffer: make(chan Message, 16),
- access: semaphore.New(1),
- done: done.New(),
- }
- s := &serverityLogger{
- inner: g,
- logLevel: serverity,
- }
- RegisterHandler(s)
- }
- func (l *serverityLogger) Handle(msg Message) {
- switch msg := msg.(type) {
- case *GeneralMessage:
- if msg.Severity <= l.logLevel {
- l.inner.Handle(msg)
- }
- default:
- l.inner.Handle(msg)
- }
- }
- func (l *generalLogger) run() {
- defer l.access.Signal()
- dataWritten := false
- ticker := time.NewTicker(time.Minute)
- defer ticker.Stop()
- logger := l.creator()
- if logger == nil {
- return
- }
- defer logger.Close()
- for {
- select {
- case <-l.done.Wait():
- return
- case msg := <-l.buffer:
- logger.Write(msg.String() + platform.LineSeparator())
- dataWritten = true
- case <-ticker.C:
- if !dataWritten {
- return
- }
- dataWritten = false
- }
- }
- }
- func (l *generalLogger) Handle(msg Message) {
- select {
- case l.buffer <- msg:
- default:
- }
- select {
- case <-l.access.Wait():
- go l.run()
- default:
- }
- }
- func (l *generalLogger) Close() error {
- return l.done.Close()
- }
- type consoleLogWriter struct {
- logger *log.Logger
- }
- func (w *consoleLogWriter) Write(s string) error {
- w.logger.Print(s)
- return nil
- }
- func (w *consoleLogWriter) Close() error {
- return nil
- }
- type fileLogWriter struct {
- file *os.File
- logger *log.Logger
- }
- func (w *fileLogWriter) Write(s string) error {
- w.logger.Print(s)
- return nil
- }
- func (w *fileLogWriter) Close() error {
- return w.file.Close()
- }
- // CreateStdoutLogWriter returns a LogWriterCreator that creates LogWriter for stdout.
- func CreateStdoutLogWriter() WriterCreator {
- return func() Writer {
- return &consoleLogWriter{
- logger: log.New(os.Stdout, "", log.Ldate|log.Ltime),
- }
- }
- }
- // CreateStderrLogWriter returns a LogWriterCreator that creates LogWriter for stderr.
- func CreateStderrLogWriter() WriterCreator {
- return func() Writer {
- return &consoleLogWriter{
- logger: log.New(os.Stderr, "", log.Ldate|log.Ltime),
- }
- }
- }
- // CreateFileLogWriter returns a LogWriterCreator that creates LogWriter for the given file.
- func CreateFileLogWriter(path string) (WriterCreator, error) {
- file, err := os.OpenFile(path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0o600)
- if err != nil {
- return nil, err
- }
- file.Close()
- return func() Writer {
- file, err := os.OpenFile(path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0o600)
- if err != nil {
- return nil
- }
- return &fileLogWriter{
- file: file,
- logger: log.New(file, "", log.Ldate|log.Ltime),
- }
- }, nil
- }
- func init() {
- RegisterHandler(NewLogger(CreateStdoutLogWriter()))
- }
|