瀏覽代碼

logger service

Darien Raymond 7 年之前
父節點
當前提交
c48fa50ab1

+ 50 - 0
app/log/command/command.go

@@ -0,0 +1,50 @@
+package command
+
+//go:generate go run $GOPATH/src/v2ray.com/core/common/errors/errorgen/main.go -pkg command -path App,Log,Command
+
+import (
+	context "golang.org/x/net/context"
+	grpc "google.golang.org/grpc"
+
+	"v2ray.com/core"
+	"v2ray.com/core/app/log"
+	"v2ray.com/core/common"
+)
+
+type LoggerServer struct {
+	V *core.Instance
+}
+
+func (s *LoggerServer) RestartLogger(ctx context.Context, request *RestartLoggerRequest) (*RestartLoggerResponse, error) {
+	logger := s.V.GetFeature((*log.Instance)(nil))
+	if logger == nil {
+		return nil, newError("unable to get logger instance")
+	}
+	if err := logger.Close(); err != nil {
+		return nil, newError("failed to close logger").Base(err)
+	}
+	if err := logger.Start(); err != nil {
+		return nil, newError("failed to start logger").Base(err)
+	}
+	return &RestartLoggerResponse{}, nil
+}
+
+type service struct {
+	v *core.Instance
+}
+
+func (s *service) Register(server *grpc.Server) {
+	RegisterLoggerServiceServer(server, &LoggerServer{
+		V: s.v,
+	})
+}
+
+func init() {
+	common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, cfg interface{}) (interface{}, error) {
+		s := core.FromContext(ctx)
+		if s == nil {
+			return nil, newError("V is not in context.")
+		}
+		return &service{v: s}, nil
+	}))
+}

+ 31 - 0
app/log/command/command_test.go

@@ -0,0 +1,31 @@
+package command_test
+
+import (
+	"context"
+	"testing"
+
+	"v2ray.com/core"
+	"v2ray.com/core/app/log"
+	. "v2ray.com/core/app/log/command"
+	"v2ray.com/core/common/serial"
+	. "v2ray.com/ext/assert"
+)
+
+func TestLoggerRestart(t *testing.T) {
+	assert := With(t)
+
+	v, err := core.New(&core.Config{
+		App: []*serial.TypedMessage{
+			serial.ToTypedMessage(&log.Config{}),
+		},
+	})
+
+	assert(err, IsNil)
+	assert(v.Start(), IsNil)
+
+	server := &LoggerServer{
+		V: v,
+	}
+	_, err = server.RestartLogger(context.Background(), &RestartLoggerRequest{})
+	assert(err, IsNil)
+}

+ 143 - 0
app/log/command/config.pb.go

@@ -0,0 +1,143 @@
+package command
+
+import proto "github.com/golang/protobuf/proto"
+import fmt "fmt"
+import math "math"
+
+import (
+	context "golang.org/x/net/context"
+	grpc "google.golang.org/grpc"
+)
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ = proto.Marshal
+var _ = fmt.Errorf
+var _ = math.Inf
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the proto package it is being compiled against.
+// A compilation error at this line likely means your copy of the
+// proto package needs to be updated.
+const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
+
+type Config struct {
+}
+
+func (m *Config) Reset()                    { *m = Config{} }
+func (m *Config) String() string            { return proto.CompactTextString(m) }
+func (*Config) ProtoMessage()               {}
+func (*Config) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
+
+type RestartLoggerRequest struct {
+}
+
+func (m *RestartLoggerRequest) Reset()                    { *m = RestartLoggerRequest{} }
+func (m *RestartLoggerRequest) String() string            { return proto.CompactTextString(m) }
+func (*RestartLoggerRequest) ProtoMessage()               {}
+func (*RestartLoggerRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
+
+type RestartLoggerResponse struct {
+}
+
+func (m *RestartLoggerResponse) Reset()                    { *m = RestartLoggerResponse{} }
+func (m *RestartLoggerResponse) String() string            { return proto.CompactTextString(m) }
+func (*RestartLoggerResponse) ProtoMessage()               {}
+func (*RestartLoggerResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
+
+func init() {
+	proto.RegisterType((*Config)(nil), "v2ray.core.app.log.command.Config")
+	proto.RegisterType((*RestartLoggerRequest)(nil), "v2ray.core.app.log.command.RestartLoggerRequest")
+	proto.RegisterType((*RestartLoggerResponse)(nil), "v2ray.core.app.log.command.RestartLoggerResponse")
+}
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ context.Context
+var _ grpc.ClientConn
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+const _ = grpc.SupportPackageIsVersion4
+
+// Client API for LoggerService service
+
+type LoggerServiceClient interface {
+	RestartLogger(ctx context.Context, in *RestartLoggerRequest, opts ...grpc.CallOption) (*RestartLoggerResponse, error)
+}
+
+type loggerServiceClient struct {
+	cc *grpc.ClientConn
+}
+
+func NewLoggerServiceClient(cc *grpc.ClientConn) LoggerServiceClient {
+	return &loggerServiceClient{cc}
+}
+
+func (c *loggerServiceClient) RestartLogger(ctx context.Context, in *RestartLoggerRequest, opts ...grpc.CallOption) (*RestartLoggerResponse, error) {
+	out := new(RestartLoggerResponse)
+	err := grpc.Invoke(ctx, "/v2ray.core.app.log.command.LoggerService/RestartLogger", in, out, c.cc, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+// Server API for LoggerService service
+
+type LoggerServiceServer interface {
+	RestartLogger(context.Context, *RestartLoggerRequest) (*RestartLoggerResponse, error)
+}
+
+func RegisterLoggerServiceServer(s *grpc.Server, srv LoggerServiceServer) {
+	s.RegisterService(&_LoggerService_serviceDesc, srv)
+}
+
+func _LoggerService_RestartLogger_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(RestartLoggerRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(LoggerServiceServer).RestartLogger(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/v2ray.core.app.log.command.LoggerService/RestartLogger",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(LoggerServiceServer).RestartLogger(ctx, req.(*RestartLoggerRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+var _LoggerService_serviceDesc = grpc.ServiceDesc{
+	ServiceName: "v2ray.core.app.log.command.LoggerService",
+	HandlerType: (*LoggerServiceServer)(nil),
+	Methods: []grpc.MethodDesc{
+		{
+			MethodName: "RestartLogger",
+			Handler:    _LoggerService_RestartLogger_Handler,
+		},
+	},
+	Streams:  []grpc.StreamDesc{},
+	Metadata: "v2ray.com/core/app/log/command/config.proto",
+}
+
+func init() { proto.RegisterFile("v2ray.com/core/app/log/command/config.proto", fileDescriptor0) }
+
+var fileDescriptor0 = []byte{
+	// 210 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xd2, 0x2e, 0x33, 0x2a, 0x4a,
+	0xac, 0xd4, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xce, 0x2f, 0x4a, 0xd5, 0x4f, 0x2c, 0x28, 0xd0, 0xcf,
+	0xc9, 0x4f, 0xd7, 0x4f, 0xce, 0xcf, 0xcd, 0x4d, 0xcc, 0x4b, 0xd1, 0x4f, 0xce, 0xcf, 0x4b, 0xcb,
+	0x4c, 0xd7, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x92, 0x82, 0x29, 0x2e, 0x4a, 0xd5, 0x4b, 0x2c,
+	0x28, 0xd0, 0xcb, 0xc9, 0x4f, 0xd7, 0x83, 0x2a, 0x54, 0xe2, 0xe0, 0x62, 0x73, 0x06, 0xab, 0x55,
+	0x12, 0xe3, 0x12, 0x09, 0x4a, 0x2d, 0x2e, 0x49, 0x2c, 0x2a, 0xf1, 0xc9, 0x4f, 0x4f, 0x4f, 0x2d,
+	0x0a, 0x4a, 0x2d, 0x2c, 0x4d, 0x2d, 0x2e, 0x51, 0x12, 0xe7, 0x12, 0x45, 0x13, 0x2f, 0x2e, 0xc8,
+	0xcf, 0x2b, 0x4e, 0x35, 0x6a, 0x67, 0xe4, 0xe2, 0x85, 0x08, 0x05, 0xa7, 0x16, 0x95, 0x65, 0x26,
+	0xa7, 0x0a, 0x95, 0x71, 0xf1, 0xa2, 0x28, 0x15, 0x32, 0xd0, 0xc3, 0x6d, 0xb5, 0x1e, 0x36, 0xdb,
+	0xa4, 0x0c, 0x49, 0xd0, 0x01, 0x71, 0x87, 0x12, 0x83, 0x93, 0x07, 0x97, 0x5c, 0x72, 0x7e, 0x2e,
+	0x1e, 0x9d, 0x01, 0x8c, 0x51, 0xec, 0x50, 0xe6, 0x2a, 0x26, 0xa9, 0x30, 0xa3, 0xa0, 0xc4, 0x4a,
+	0x3d, 0x67, 0x90, 0x3a, 0xc7, 0x82, 0x02, 0x3d, 0x9f, 0xfc, 0x74, 0x3d, 0x67, 0x88, 0x64, 0x12,
+	0x1b, 0x38, 0xc4, 0x8c, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, 0x37, 0xc7, 0xfc, 0xda, 0x60, 0x01,
+	0x00, 0x00,
+}

+ 18 - 0
app/log/command/config.proto

@@ -0,0 +1,18 @@
+syntax = "proto3";
+
+package v2ray.core.app.log.command;
+option csharp_namespace = "V2Ray.Core.App.Log.Command";
+option go_package = "command";
+option java_package = "com.v2ray.core.app.log.command";
+option java_multiple_files = true;
+
+message Config {
+}
+
+message RestartLoggerRequest {}
+
+message RestartLoggerResponse{}
+
+service LoggerService {
+  rpc RestartLogger(RestartLoggerRequest) returns (RestartLoggerResponse) {}
+}

+ 5 - 0
app/log/command/errors.generated.go

@@ -0,0 +1,5 @@
+package command
+
+import "v2ray.com/core/common/errors"
+
+func newError(values ...interface{}) *errors.Error { return errors.New(values...).Path("App", "Log", "Command") }

+ 36 - 13
app/log/log.go

@@ -6,6 +6,7 @@ import (
 	"context"
 	"sync"
 
+	"v2ray.com/core"
 	"v2ray.com/core/common"
 	"v2ray.com/core/common/log"
 )
@@ -26,13 +27,10 @@ func New(ctx context.Context, config *Config) (*Instance, error) {
 		active: true,
 	}
 
-	if err := g.initAccessLogger(); err != nil {
-		return nil, newError("failed to initialize access logger").Base(err).AtWarning()
-	}
-	if err := g.initErrorLogger(); err != nil {
-		return nil, newError("failed to initialize error logger").Base(err).AtWarning()
+	v := core.FromContext(ctx)
+	if v != nil {
+		common.Must(v.RegisterFeature((*log.Handler)(nil), g))
 	}
-	log.RegisterHandler(g)
 
 	return g, nil
 }
@@ -67,24 +65,40 @@ func (g *Instance) initErrorLogger() error {
 	return nil
 }
 
+func (*Instance) Type() interface{} {
+	return (*Instance)(nil)
+}
+
 // Start implements app.Application.Start().
 func (g *Instance) Start() error {
+	newError("Logger starting").AtDebug().WriteToLog()
+
 	g.Lock()
 	defer g.Unlock()
+
+	if g.active {
+		return nil
+	}
+
 	g.active = true
-	return nil
-}
 
-func (g *Instance) isActive() bool {
-	g.RLock()
-	defer g.RUnlock()
+	if err := g.initAccessLogger(); err != nil {
+		return newError("failed to initialize access logger").Base(err).AtWarning()
+	}
+	if err := g.initErrorLogger(); err != nil {
+		return newError("failed to initialize error logger").Base(err).AtWarning()
+	}
+	log.RegisterHandler(g)
 
-	return g.active
+	return nil
 }
 
 // Handle implements log.Handler.
 func (g *Instance) Handle(msg log.Message) {
-	if !g.isActive() {
+	g.RLock()
+	defer g.RUnlock()
+
+	if !g.active {
 		return
 	}
 
@@ -104,11 +118,20 @@ func (g *Instance) Handle(msg log.Message) {
 
 // Close implement app.Application.Close().
 func (g *Instance) Close() error {
+	newError("Logger closing").AtDebug().WriteToLog()
+
 	g.Lock()
 	defer g.Unlock()
 
+	if !g.active {
+		return nil
+	}
+
 	g.active = false
 
+	common.Close(g.accessLogger)
+	common.Close(g.errorLogger)
+
 	return nil
 }
 

+ 6 - 0
common/interfaces.go

@@ -21,3 +21,9 @@ type Runnable interface {
 
 	Closable
 }
+
+// HasType is the interface for objects that knows its type.
+type HasType interface {
+	// Type returns the type of the object.
+	Type() interface{}
+}

+ 8 - 0
common/log/logger.go

@@ -23,6 +23,7 @@ type generalLogger struct {
 	creator WriterCreator
 	buffer  chan Message
 	access  *signal.Semaphore
+	done    *signal.Done
 }
 
 // NewLogger returns a generic log handler that can handle all type of messages.
@@ -31,6 +32,7 @@ func NewLogger(logWriterCreator WriterCreator) Handler {
 		creator: logWriterCreator,
 		buffer:  make(chan Message, 16),
 		access:  signal.NewSemaphore(1),
+		done:    signal.NewDone(),
 	}
 }
 
@@ -49,6 +51,8 @@ func (l *generalLogger) run() {
 
 	for {
 		select {
+		case <-l.done.C():
+			return
 		case msg := <-l.buffer:
 			logger.Write(msg.String() + platform.LineSeparator())
 			dataWritten = true
@@ -74,6 +78,10 @@ func (l *generalLogger) Handle(msg Message) {
 	}
 }
 
+func (l *generalLogger) Close() error {
+	return l.done.Close()
+}
+
 type consoleLogWriter struct {
 	logger *log.Logger
 }

+ 12 - 0
v2ray.go

@@ -163,6 +163,18 @@ func (s *Instance) RegisterFeature(feature interface{}, instance Feature) error
 	return nil
 }
 
+// GetFeature returns a feature that was registered in this Instance. Nil if not found.
+func (s *Instance) GetFeature(featureType interface{}) Feature {
+	for _, f := range s.features {
+		if hasType, ok := f.(common.HasType); ok {
+			if hasType.Type() == featureType {
+				return f
+			}
+		}
+	}
+	return nil
+}
+
 // DNSClient returns the DNSClient used by this Instance. The returned DNSClient is always functional.
 func (s *Instance) DNSClient() DNSClient {
 	return &(s.dnsClient)