github.com/v2fly/v2ray-core/v5@v5.16.2-0.20240507031116-8191faa6e095/app/log/log.go (about)

     1  package log
     2  
     3  //go:generate go run github.com/v2fly/v2ray-core/v5/common/errors/errorgen
     4  
     5  import (
     6  	"context"
     7  	"reflect"
     8  	"sync"
     9  
    10  	"github.com/v2fly/v2ray-core/v5/common"
    11  	"github.com/v2fly/v2ray-core/v5/common/log"
    12  )
    13  
    14  // Instance is a log.Handler that handles logs.
    15  type Instance struct {
    16  	sync.RWMutex
    17  	config       *Config
    18  	accessLogger log.Handler
    19  	errorLogger  log.Handler
    20  	followers    map[reflect.Value]func(msg log.Message)
    21  	active       bool
    22  }
    23  
    24  // New creates a new log.Instance based on the given config.
    25  func New(ctx context.Context, config *Config) (*Instance, error) {
    26  	if config.Error == nil {
    27  		config.Error = &LogSpecification{Type: LogType_Console, Level: log.Severity_Warning}
    28  	}
    29  
    30  	if config.Access == nil {
    31  		config.Access = &LogSpecification{Type: LogType_None}
    32  	}
    33  
    34  	g := &Instance{
    35  		config: config,
    36  		active: false,
    37  	}
    38  	log.RegisterHandler(g)
    39  
    40  	// start logger instantly on inited
    41  	// other modules would log during init
    42  	if err := g.startInternal(); err != nil {
    43  		return nil, err
    44  	}
    45  
    46  	newError("Logger started").AtDebug().WriteToLog()
    47  	return g, nil
    48  }
    49  
    50  func (g *Instance) initAccessLogger() error {
    51  	handler, err := createHandler(g.config.Access.Type, HandlerCreatorOptions{
    52  		Path: g.config.Access.Path,
    53  	})
    54  	if err != nil {
    55  		return err
    56  	}
    57  	g.accessLogger = handler
    58  	return nil
    59  }
    60  
    61  func (g *Instance) initErrorLogger() error {
    62  	handler, err := createHandler(g.config.Error.Type, HandlerCreatorOptions{
    63  		Path: g.config.Error.Path,
    64  	})
    65  	if err != nil {
    66  		return err
    67  	}
    68  	g.errorLogger = handler
    69  	return nil
    70  }
    71  
    72  // Type implements common.HasType.
    73  func (*Instance) Type() interface{} {
    74  	return (*Instance)(nil)
    75  }
    76  
    77  func (g *Instance) startInternal() error {
    78  	g.Lock()
    79  	defer g.Unlock()
    80  
    81  	if g.active {
    82  		return nil
    83  	}
    84  
    85  	g.active = true
    86  
    87  	if err := g.initAccessLogger(); err != nil {
    88  		return newError("failed to initialize access logger").Base(err).AtWarning()
    89  	}
    90  	if err := g.initErrorLogger(); err != nil {
    91  		return newError("failed to initialize error logger").Base(err).AtWarning()
    92  	}
    93  
    94  	return nil
    95  }
    96  
    97  // Start implements common.Runnable.Start().
    98  func (g *Instance) Start() error {
    99  	return g.startInternal()
   100  }
   101  
   102  // AddFollower implements log.Follower.
   103  func (g *Instance) AddFollower(f func(msg log.Message)) {
   104  	g.Lock()
   105  	defer g.Unlock()
   106  	if g.followers == nil {
   107  		g.followers = make(map[reflect.Value]func(msg log.Message))
   108  	}
   109  	g.followers[reflect.ValueOf(f)] = f
   110  }
   111  
   112  // RemoveFollower implements log.Follower.
   113  func (g *Instance) RemoveFollower(f func(msg log.Message)) {
   114  	g.Lock()
   115  	defer g.Unlock()
   116  	delete(g.followers, reflect.ValueOf(f))
   117  }
   118  
   119  // Handle implements log.Handler.
   120  func (g *Instance) Handle(msg log.Message) {
   121  	g.RLock()
   122  	defer g.RUnlock()
   123  
   124  	if !g.active {
   125  		return
   126  	}
   127  
   128  	for _, f := range g.followers {
   129  		f(msg)
   130  	}
   131  
   132  	switch msg := msg.(type) {
   133  	case *log.AccessMessage:
   134  		if g.accessLogger != nil {
   135  			g.accessLogger.Handle(msg)
   136  		}
   137  	case *log.GeneralMessage:
   138  		if g.errorLogger != nil && msg.Severity <= g.config.Error.Level {
   139  			g.errorLogger.Handle(msg)
   140  		}
   141  	default:
   142  		// Swallow
   143  	}
   144  }
   145  
   146  // Close implements common.Closable.Close().
   147  func (g *Instance) Close() error {
   148  	newError("Logger closing").AtDebug().WriteToLog()
   149  
   150  	g.Lock()
   151  	defer g.Unlock()
   152  
   153  	if !g.active {
   154  		return nil
   155  	}
   156  
   157  	g.active = false
   158  
   159  	common.Close(g.accessLogger)
   160  	g.accessLogger = nil
   161  
   162  	common.Close(g.errorLogger)
   163  	g.errorLogger = nil
   164  
   165  	return nil
   166  }
   167  
   168  func init() {
   169  	common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
   170  		return New(ctx, config.(*Config))
   171  	}))
   172  }