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 }