Browse Source

support custom log handler

Darien Raymond 7 years ago
parent
commit
30b5bffad4
5 changed files with 160 additions and 20 deletions
  1. 12 20
      app/log/log.go
  2. 51 0
      app/log/log_creator.go
  3. 52 0
      app/log/log_test.go
  4. 1 0
      mocks.go
  5. 44 0
      testing/mocks/log.go

+ 12 - 20
app/log/log.go

@@ -31,32 +31,24 @@ func New(ctx context.Context, config *Config) (*Instance, error) {
 }
 }
 
 
 func (g *Instance) initAccessLogger() error {
 func (g *Instance) initAccessLogger() error {
-	switch g.config.AccessLogType {
-	case LogType_File:
-		creator, err := log.CreateFileLogWriter(g.config.AccessLogPath)
-		if err != nil {
-			return err
-		}
-		g.accessLogger = log.NewLogger(creator)
-	case LogType_Console:
-		g.accessLogger = log.NewLogger(log.CreateStdoutLogWriter())
-	default:
+	handler, err := createHandler(g.config.AccessLogType, HandlerCreatorOptions{
+		Path: g.config.AccessLogPath,
+	})
+	if err != nil {
+		return err
 	}
 	}
+	g.accessLogger = handler
 	return nil
 	return nil
 }
 }
 
 
 func (g *Instance) initErrorLogger() error {
 func (g *Instance) initErrorLogger() error {
-	switch g.config.ErrorLogType {
-	case LogType_File:
-		creator, err := log.CreateFileLogWriter(g.config.ErrorLogPath)
-		if err != nil {
-			return err
-		}
-		g.errorLogger = log.NewLogger(creator)
-	case LogType_Console:
-		g.errorLogger = log.NewLogger(log.CreateStdoutLogWriter())
-	default:
+	handler, err := createHandler(g.config.ErrorLogType, HandlerCreatorOptions{
+		Path: g.config.ErrorLogPath,
+	})
+	if err != nil {
+		return err
 	}
 	}
+	g.errorLogger = handler
 	return nil
 	return nil
 }
 }
 
 

+ 51 - 0
app/log/log_creator.go

@@ -0,0 +1,51 @@
+package log
+
+import (
+	"v2ray.com/core/common"
+	"v2ray.com/core/common/log"
+)
+
+type HandlerCreatorOptions struct {
+	Path string
+}
+
+type HandlerCreator func(LogType, HandlerCreatorOptions) (log.Handler, error)
+
+var (
+	handlerCreatorMap = make(map[LogType]HandlerCreator)
+)
+
+func RegisterHandlerCreator(logType LogType, f HandlerCreator) error {
+	if f == nil {
+		return newError("nil HandlerCreator")
+	}
+
+	handlerCreatorMap[logType] = f
+	return nil
+}
+
+func createHandler(logType LogType, options HandlerCreatorOptions) (log.Handler, error) {
+	creator, found := handlerCreatorMap[logType]
+	if !found {
+		return nil, newError("unable to create log handler for ", logType)
+	}
+	return creator(logType, options)
+}
+
+func init() {
+	common.Must(RegisterHandlerCreator(LogType_Console, func(lt LogType, options HandlerCreatorOptions) (log.Handler, error) {
+		return log.NewLogger(log.CreateStdoutLogWriter()), nil
+	}))
+
+	common.Must(RegisterHandlerCreator(LogType_File, func(lt LogType, options HandlerCreatorOptions) (log.Handler, error) {
+		creator, err := log.CreateFileLogWriter(options.Path)
+		if err != nil {
+			return nil, err
+		}
+		return log.NewLogger(creator), nil
+	}))
+
+	common.Must(RegisterHandlerCreator(LogType_None, func(lt LogType, options HandlerCreatorOptions) (log.Handler, error) {
+		return nil, nil
+	}))
+}

+ 52 - 0
app/log/log_test.go

@@ -0,0 +1,52 @@
+package log_test
+
+import (
+	"context"
+	"testing"
+
+	"github.com/golang/mock/gomock"
+	"v2ray.com/core/app/log"
+	"v2ray.com/core/common"
+	clog "v2ray.com/core/common/log"
+	"v2ray.com/core/testing/mocks"
+)
+
+func TestCustomLogHandler(t *testing.T) {
+	mockCtl := gomock.NewController(t)
+	defer mockCtl.Finish()
+
+	var loggedValue []string
+
+	mockHandler := mocks.NewLogHandler(mockCtl)
+	mockHandler.EXPECT().Handle(gomock.Any()).AnyTimes().DoAndReturn(func(msg clog.Message) {
+		loggedValue = append(loggedValue, msg.String())
+	})
+
+	log.RegisterHandlerCreator(log.LogType_Console, func(lt log.LogType, options log.HandlerCreatorOptions) (clog.Handler, error) {
+		return mockHandler, nil
+	})
+
+	logger, err := log.New(context.Background(), &log.Config{
+		ErrorLogLevel: clog.Severity_Debug,
+		ErrorLogType:  log.LogType_Console,
+		AccessLogType: log.LogType_None,
+	})
+	common.Must(err)
+
+	common.Must(logger.Start())
+
+	clog.Record(&clog.GeneralMessage{
+		Severity: clog.Severity_Debug,
+		Content:  "test",
+	})
+
+	if len(loggedValue) < 2 {
+		t.Fatal("expected 2 log messages, but actually ", loggedValue)
+	}
+
+	if loggedValue[1] != "[Debug] test" {
+		t.Fatal("expected '[Debug] test', but actually ", loggedValue[1])
+	}
+
+	common.Must(logger.Close())
+}

+ 1 - 0
mocks.go

@@ -4,6 +4,7 @@ package core
 //go:generate go install github.com/golang/mock/mockgen
 //go:generate go install github.com/golang/mock/mockgen
 
 
 //go:generate mockgen -package mocks -destination testing/mocks/io.go -mock_names Reader=Reader,Writer=Writer io Reader,Writer
 //go:generate mockgen -package mocks -destination testing/mocks/io.go -mock_names Reader=Reader,Writer=Writer io Reader,Writer
+//go:generate mockgen -package mocks -destination testing/mocks/log.go -mock_names Handler=LogHandler v2ray.com/core/common/log Handler
 //go:generate mockgen -package mocks -destination testing/mocks/mux.go -mock_names ClientWorkerFactory=MuxClientWorkerFactory v2ray.com/core/common/mux ClientWorkerFactory
 //go:generate mockgen -package mocks -destination testing/mocks/mux.go -mock_names ClientWorkerFactory=MuxClientWorkerFactory v2ray.com/core/common/mux ClientWorkerFactory
 //go:generate mockgen -package mocks -destination testing/mocks/dns.go -mock_names Client=DNSClient v2ray.com/core/features/dns Client
 //go:generate mockgen -package mocks -destination testing/mocks/dns.go -mock_names Client=DNSClient v2ray.com/core/features/dns Client
 //go:generate mockgen -package mocks -destination testing/mocks/outbound.go -mock_names Manager=OutboundManager,HandlerSelector=OutboundHandlerSelector v2ray.com/core/features/outbound Manager,HandlerSelector
 //go:generate mockgen -package mocks -destination testing/mocks/outbound.go -mock_names Manager=OutboundManager,HandlerSelector=OutboundHandlerSelector v2ray.com/core/features/outbound Manager,HandlerSelector

+ 44 - 0
testing/mocks/log.go

@@ -0,0 +1,44 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: v2ray.com/core/common/log (interfaces: Handler)
+
+// Package mocks is a generated GoMock package.
+package mocks
+
+import (
+	gomock "github.com/golang/mock/gomock"
+	reflect "reflect"
+	log "v2ray.com/core/common/log"
+)
+
+// LogHandler is a mock of Handler interface
+type LogHandler struct {
+	ctrl     *gomock.Controller
+	recorder *LogHandlerMockRecorder
+}
+
+// LogHandlerMockRecorder is the mock recorder for LogHandler
+type LogHandlerMockRecorder struct {
+	mock *LogHandler
+}
+
+// NewLogHandler creates a new mock instance
+func NewLogHandler(ctrl *gomock.Controller) *LogHandler {
+	mock := &LogHandler{ctrl: ctrl}
+	mock.recorder = &LogHandlerMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use
+func (m *LogHandler) EXPECT() *LogHandlerMockRecorder {
+	return m.recorder
+}
+
+// Handle mocks base method
+func (m *LogHandler) Handle(arg0 log.Message) {
+	m.ctrl.Call(m, "Handle", arg0)
+}
+
+// Handle indicates an expected call of Handle
+func (mr *LogHandlerMockRecorder) Handle(arg0 interface{}) *gomock.Call {
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Handle", reflect.TypeOf((*LogHandler)(nil).Handle), arg0)
+}