|  |  | @ -8,21 +8,44 @@ import ( | 
			
		
	
		
			
				
					|  |  |  | 	"runtime" | 
			
		
	
		
			
				
					|  |  |  | ) | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | type logger struct { | 
			
		
	
		
			
				
					|  |  |  | 	logger  *zap.Logger | 
			
		
	
		
			
				
					|  |  |  | 	level   *zap.AtomicLevel | 
			
		
	
		
			
				
					|  |  |  | 	sugar   *zap.SugaredLogger | 
			
		
	
		
			
				
					|  |  |  | var project string  // project absolute path
 | 
			
		
	
		
			
				
					|  |  |  | var logger *logCore // singleton logger handle
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | // logChannel handle multiple writers with unified format.
 | 
			
		
	
		
			
				
					|  |  |  | type logChannel struct { | 
			
		
	
		
			
				
					|  |  |  | 	encoder zapcore.Encoder | 
			
		
	
		
			
				
					|  |  |  | 	writers []zapcore.WriteSyncer | 
			
		
	
		
			
				
					|  |  |  | 	stderr  zapcore.Core // fixed stderr output
 | 
			
		
	
		
			
				
					|  |  |  | } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | // logCore manage log level, channels and other interfaces.
 | 
			
		
	
		
			
				
					|  |  |  | type logCore struct { | 
			
		
	
		
			
				
					|  |  |  | 	prefix  string // custom output prefix
 | 
			
		
	
		
			
				
					|  |  |  | 	path    string       // project absolute path
 | 
			
		
	
		
			
				
					|  |  |  | 	verbose bool         // show goroutine id and caller line
 | 
			
		
	
		
			
				
					|  |  |  | 	verbose bool   // show verbose information
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 	plain   logChannel // log channel with plain text
 | 
			
		
	
		
			
				
					|  |  |  | 	colored logChannel // log channel with colored text
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 	level *zap.AtomicLevel   // zap log level pointer
 | 
			
		
	
		
			
				
					|  |  |  | 	entry *zap.SugaredLogger // zap sugared logger entry
 | 
			
		
	
		
			
				
					|  |  |  | } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | var logHandle *logger // singleton logger handle
 | 
			
		
	
		
			
				
					|  |  |  | func init() { | 
			
		
	
		
			
				
					|  |  |  | 	_, src, _, _ := runtime.Caller(0) // absolute path of current code
 | 
			
		
	
		
			
				
					|  |  |  | 	project = path.Join(path.Dir(src), "../") | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 	zapLevel := zap.NewAtomicLevelAt(InfoLevel) // using info level in default
 | 
			
		
	
		
			
				
					|  |  |  | 	logger = &logCore{ | 
			
		
	
		
			
				
					|  |  |  | 		verbose: false, | 
			
		
	
		
			
				
					|  |  |  | 		level:   &zapLevel, | 
			
		
	
		
			
				
					|  |  |  | 		prefix:  "[XProxy]", | 
			
		
	
		
			
				
					|  |  |  | 		plain:   buildChannel(false), | 
			
		
	
		
			
				
					|  |  |  | 		colored: buildChannel(true), | 
			
		
	
		
			
				
					|  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  | 	logger.addColoredWrites(os.Stderr) // output into stderr in default
 | 
			
		
	
		
			
				
					|  |  |  | } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | // logConfig generates log config for XProxy.
 | 
			
		
	
		
			
				
					|  |  |  | func logConfig(colored bool) zapcore.EncoderConfig { | 
			
		
	
		
			
				
					|  |  |  | // buildChannel generate logChannel with `colored` option.
 | 
			
		
	
		
			
				
					|  |  |  | func buildChannel(colored bool) logChannel { | 
			
		
	
		
			
				
					|  |  |  | 	config := zapcore.EncoderConfig{ | 
			
		
	
		
			
				
					|  |  |  | 		ConsoleSeparator: " ", | 
			
		
	
		
			
				
					|  |  |  | 		MessageKey:       "msg", | 
			
		
	
	
		
			
				
					|  |  | @ -33,46 +56,40 @@ func logConfig(colored bool) zapcore.EncoderConfig { | 
			
		
	
		
			
				
					|  |  |  | 		EncodeLevel:      levelEncoder, | 
			
		
	
		
			
				
					|  |  |  | 		EncodeCaller:     callerEncoder, | 
			
		
	
		
			
				
					|  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  | 	if colored { | 
			
		
	
		
			
				
					|  |  |  | 	if colored { // using colored version
 | 
			
		
	
		
			
				
					|  |  |  | 		config.EncodeTime = timeColoredEncoder | 
			
		
	
		
			
				
					|  |  |  | 		config.EncodeLevel = levelColoredEncoder | 
			
		
	
		
			
				
					|  |  |  | 		config.EncodeCaller = callerColoredEncoder | 
			
		
	
		
			
				
					|  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  | 	return config | 
			
		
	
		
			
				
					|  |  |  | 	return logChannel{ | 
			
		
	
		
			
				
					|  |  |  | 		encoder: zapcore.NewConsoleEncoder(config), | 
			
		
	
		
			
				
					|  |  |  | 		writers: []zapcore.WriteSyncer{}, // without any writer
 | 
			
		
	
		
			
				
					|  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  | } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | func init() { | 
			
		
	
		
			
				
					|  |  |  | 	zapLevel := zap.NewAtomicLevelAt(InfoLevel) // using info level in default
 | 
			
		
	
		
			
				
					|  |  |  | 	zapCore := zapcore.NewCore( | 
			
		
	
		
			
				
					|  |  |  | 		zapcore.NewConsoleEncoder(logConfig(true)), // colorful output
 | 
			
		
	
		
			
				
					|  |  |  | 		zapcore.Lock(os.Stderr), | 
			
		
	
		
			
				
					|  |  |  | 		zapLevel, | 
			
		
	
		
			
				
					|  |  |  | // update refreshes the binding of the log core to the writers.
 | 
			
		
	
		
			
				
					|  |  |  | func (handle *logCore) update() { | 
			
		
	
		
			
				
					|  |  |  | 	buildCore := func(channel *logChannel) zapcore.Core { // build zap core from logChannel
 | 
			
		
	
		
			
				
					|  |  |  | 		return zapcore.NewCore( | 
			
		
	
		
			
				
					|  |  |  | 			channel.encoder, | 
			
		
	
		
			
				
					|  |  |  | 			zap.CombineWriteSyncers(channel.writers...), | 
			
		
	
		
			
				
					|  |  |  | 			handle.level, | 
			
		
	
		
			
				
					|  |  |  | 		) | 
			
		
	
		
			
				
					|  |  |  | 	zapLogger := zap.New(zapCore, zap.AddCaller(), zap.AddCallerSkip(1)) | 
			
		
	
		
			
				
					|  |  |  | 	_, src, _, _ := runtime.Caller(0) // absolute path of current code
 | 
			
		
	
		
			
				
					|  |  |  | 	logHandle = &logger{ | 
			
		
	
		
			
				
					|  |  |  | 		logger:  zapLogger, | 
			
		
	
		
			
				
					|  |  |  | 		level:   &zapLevel, | 
			
		
	
		
			
				
					|  |  |  | 		stderr:  zapCore, | 
			
		
	
		
			
				
					|  |  |  | 		sugar:   zapLogger.Sugar(), | 
			
		
	
		
			
				
					|  |  |  | 		writers: []zapcore.WriteSyncer{}, | 
			
		
	
		
			
				
					|  |  |  | 		path:    path.Join(path.Dir(src), "../"), | 
			
		
	
		
			
				
					|  |  |  | 		prefix:  "[XProxy]", | 
			
		
	
		
			
				
					|  |  |  | 		verbose: false, | 
			
		
	
		
			
				
					|  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  | 	handle.entry = zap.New( | 
			
		
	
		
			
				
					|  |  |  | 		zapcore.NewTee(buildCore(&handle.plain), buildCore(&handle.colored)), | 
			
		
	
		
			
				
					|  |  |  | 		zap.AddCaller(), zap.AddCallerSkip(1), | 
			
		
	
		
			
				
					|  |  |  | 	).Sugar() | 
			
		
	
		
			
				
					|  |  |  | } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | // addWrites adds more plain log writers.
 | 
			
		
	
		
			
				
					|  |  |  | func addWrites(writers ...zapcore.WriteSyncer) { | 
			
		
	
		
			
				
					|  |  |  | 	logHandle.writers = append(logHandle.writers, writers...) | 
			
		
	
		
			
				
					|  |  |  | 	plainCore := zapcore.NewCore( | 
			
		
	
		
			
				
					|  |  |  | 		zapcore.NewConsoleEncoder(logConfig(false)), // without colored
 | 
			
		
	
		
			
				
					|  |  |  | 		zap.CombineWriteSyncers(logHandle.writers...), | 
			
		
	
		
			
				
					|  |  |  | 		logHandle.level, | 
			
		
	
		
			
				
					|  |  |  | 	) | 
			
		
	
		
			
				
					|  |  |  | 	logHandle.logger = zap.New( | 
			
		
	
		
			
				
					|  |  |  | 		zapcore.NewTee(logHandle.stderr, plainCore), | 
			
		
	
		
			
				
					|  |  |  | 		zap.AddCaller(), zap.AddCallerSkip(1), | 
			
		
	
		
			
				
					|  |  |  | 	) | 
			
		
	
		
			
				
					|  |  |  | 	logHandle.sugar = logHandle.logger.Sugar() | 
			
		
	
		
			
				
					|  |  |  | // addPlainWrites adds plain text writers to the logCore.
 | 
			
		
	
		
			
				
					|  |  |  | func (handle *logCore) addPlainWrites(writers ...zapcore.WriteSyncer) { | 
			
		
	
		
			
				
					|  |  |  | 	handle.plain.writers = append(handle.plain.writers, writers...) | 
			
		
	
		
			
				
					|  |  |  | 	handle.update() | 
			
		
	
		
			
				
					|  |  |  | } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | // addColoredWrites adds colored text writers to the logCore.
 | 
			
		
	
		
			
				
					|  |  |  | func (handle *logCore) addColoredWrites(writers ...zapcore.WriteSyncer) { | 
			
		
	
		
			
				
					|  |  |  | 	handle.colored.writers = append(handle.colored.writers, writers...) | 
			
		
	
		
			
				
					|  |  |  | 	handle.update() | 
			
		
	
		
			
				
					|  |  |  | } | 
			
		
	
	
		
			
				
					|  |  | 
 |