mirror of
https://github.com/XTLS/Xray-core.git
synced 2025-04-29 16:58:34 +00:00
v1.0.0
This commit is contained in:
parent
47d23e9972
commit
c7f7c08ead
711 changed files with 82154 additions and 2 deletions
64
common/log/access.go
Normal file
64
common/log/access.go
Normal file
|
@ -0,0 +1,64 @@
|
|||
package log
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/xtls/xray-core/v1/common/serial"
|
||||
)
|
||||
|
||||
type logKey int
|
||||
|
||||
const (
|
||||
accessMessageKey logKey = iota
|
||||
)
|
||||
|
||||
type AccessStatus string
|
||||
|
||||
const (
|
||||
AccessAccepted = AccessStatus("accepted")
|
||||
AccessRejected = AccessStatus("rejected")
|
||||
)
|
||||
|
||||
type AccessMessage struct {
|
||||
From interface{}
|
||||
To interface{}
|
||||
Status AccessStatus
|
||||
Reason interface{}
|
||||
Email string
|
||||
Detour string
|
||||
}
|
||||
|
||||
func (m *AccessMessage) String() string {
|
||||
builder := strings.Builder{}
|
||||
builder.WriteString(serial.ToString(m.From))
|
||||
builder.WriteByte(' ')
|
||||
builder.WriteString(string(m.Status))
|
||||
builder.WriteByte(' ')
|
||||
builder.WriteString(serial.ToString(m.To))
|
||||
builder.WriteByte(' ')
|
||||
if len(m.Detour) > 0 {
|
||||
builder.WriteByte('[')
|
||||
builder.WriteString(m.Detour)
|
||||
builder.WriteString("] ")
|
||||
}
|
||||
builder.WriteString(serial.ToString(m.Reason))
|
||||
|
||||
if len(m.Email) > 0 {
|
||||
builder.WriteString("email:")
|
||||
builder.WriteString(m.Email)
|
||||
builder.WriteByte(' ')
|
||||
}
|
||||
return builder.String()
|
||||
}
|
||||
|
||||
func ContextWithAccessMessage(ctx context.Context, accessMessage *AccessMessage) context.Context {
|
||||
return context.WithValue(ctx, accessMessageKey, accessMessage)
|
||||
}
|
||||
|
||||
func AccessMessageFromContext(ctx context.Context) *AccessMessage {
|
||||
if accessMessage, ok := ctx.Value(accessMessageKey).(*AccessMessage); ok {
|
||||
return accessMessage
|
||||
}
|
||||
return nil
|
||||
}
|
66
common/log/log.go
Normal file
66
common/log/log.go
Normal file
|
@ -0,0 +1,66 @@
|
|||
package log // import "github.com/xtls/xray-core/v1/common/log"
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/xtls/xray-core/v1/common/serial"
|
||||
)
|
||||
|
||||
// Message is the interface for all log messages.
|
||||
type Message interface {
|
||||
String() string
|
||||
}
|
||||
|
||||
// Handler is the interface for log handler.
|
||||
type Handler interface {
|
||||
Handle(msg Message)
|
||||
}
|
||||
|
||||
// GeneralMessage is a general log message that can contain all kind of content.
|
||||
type GeneralMessage struct {
|
||||
Severity Severity
|
||||
Content interface{}
|
||||
}
|
||||
|
||||
// String implements Message.
|
||||
func (m *GeneralMessage) String() string {
|
||||
return serial.Concat("[", m.Severity, "] ", m.Content)
|
||||
}
|
||||
|
||||
// Record writes a message into log stream.
|
||||
func Record(msg Message) {
|
||||
logHandler.Handle(msg)
|
||||
}
|
||||
|
||||
var (
|
||||
logHandler syncHandler
|
||||
)
|
||||
|
||||
// RegisterHandler register a new handler as current log handler. Previous registered handler will be discarded.
|
||||
func RegisterHandler(handler Handler) {
|
||||
if handler == nil {
|
||||
panic("Log handler is nil")
|
||||
}
|
||||
logHandler.Set(handler)
|
||||
}
|
||||
|
||||
type syncHandler struct {
|
||||
sync.RWMutex
|
||||
Handler
|
||||
}
|
||||
|
||||
func (h *syncHandler) Handle(msg Message) {
|
||||
h.RLock()
|
||||
defer h.RUnlock()
|
||||
|
||||
if h.Handler != nil {
|
||||
h.Handler.Handle(msg)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *syncHandler) Set(handler Handler) {
|
||||
h.Lock()
|
||||
defer h.Unlock()
|
||||
|
||||
h.Handler = handler
|
||||
}
|
148
common/log/log.pb.go
Normal file
148
common/log/log.pb.go
Normal file
|
@ -0,0 +1,148 @@
|
|||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.25.0
|
||||
// protoc v3.14.0
|
||||
// source: common/log/log.proto
|
||||
|
||||
package log
|
||||
|
||||
import (
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||
// of the legacy proto package is being used.
|
||||
const _ = proto.ProtoPackageIsVersion4
|
||||
|
||||
type Severity int32
|
||||
|
||||
const (
|
||||
Severity_Unknown Severity = 0
|
||||
Severity_Error Severity = 1
|
||||
Severity_Warning Severity = 2
|
||||
Severity_Info Severity = 3
|
||||
Severity_Debug Severity = 4
|
||||
)
|
||||
|
||||
// Enum value maps for Severity.
|
||||
var (
|
||||
Severity_name = map[int32]string{
|
||||
0: "Unknown",
|
||||
1: "Error",
|
||||
2: "Warning",
|
||||
3: "Info",
|
||||
4: "Debug",
|
||||
}
|
||||
Severity_value = map[string]int32{
|
||||
"Unknown": 0,
|
||||
"Error": 1,
|
||||
"Warning": 2,
|
||||
"Info": 3,
|
||||
"Debug": 4,
|
||||
}
|
||||
)
|
||||
|
||||
func (x Severity) Enum() *Severity {
|
||||
p := new(Severity)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x Severity) String() string {
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
|
||||
func (Severity) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_common_log_log_proto_enumTypes[0].Descriptor()
|
||||
}
|
||||
|
||||
func (Severity) Type() protoreflect.EnumType {
|
||||
return &file_common_log_log_proto_enumTypes[0]
|
||||
}
|
||||
|
||||
func (x Severity) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Severity.Descriptor instead.
|
||||
func (Severity) EnumDescriptor() ([]byte, []int) {
|
||||
return file_common_log_log_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
var File_common_log_log_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_common_log_log_proto_rawDesc = []byte{
|
||||
0x0a, 0x14, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6c, 0x6f, 0x67, 0x2f, 0x6c, 0x6f, 0x67,
|
||||
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d,
|
||||
0x6d, 0x6f, 0x6e, 0x2e, 0x6c, 0x6f, 0x67, 0x2a, 0x44, 0x0a, 0x08, 0x53, 0x65, 0x76, 0x65, 0x72,
|
||||
0x69, 0x74, 0x79, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x10, 0x00,
|
||||
0x12, 0x09, 0x0a, 0x05, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x57,
|
||||
0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x49, 0x6e, 0x66, 0x6f,
|
||||
0x10, 0x03, 0x12, 0x09, 0x0a, 0x05, 0x44, 0x65, 0x62, 0x75, 0x67, 0x10, 0x04, 0x42, 0x52, 0x0a,
|
||||
0x13, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
|
||||
0x2e, 0x6c, 0x6f, 0x67, 0x50, 0x01, 0x5a, 0x27, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63,
|
||||
0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72,
|
||||
0x65, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6c, 0x6f, 0x67, 0xaa,
|
||||
0x02, 0x0f, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x6f,
|
||||
0x67, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_common_log_log_proto_rawDescOnce sync.Once
|
||||
file_common_log_log_proto_rawDescData = file_common_log_log_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_common_log_log_proto_rawDescGZIP() []byte {
|
||||
file_common_log_log_proto_rawDescOnce.Do(func() {
|
||||
file_common_log_log_proto_rawDescData = protoimpl.X.CompressGZIP(file_common_log_log_proto_rawDescData)
|
||||
})
|
||||
return file_common_log_log_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_common_log_log_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
||||
var file_common_log_log_proto_goTypes = []interface{}{
|
||||
(Severity)(0), // 0: xray.common.log.Severity
|
||||
}
|
||||
var file_common_log_log_proto_depIdxs = []int32{
|
||||
0, // [0:0] is the sub-list for method output_type
|
||||
0, // [0:0] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_common_log_log_proto_init() }
|
||||
func file_common_log_log_proto_init() {
|
||||
if File_common_log_log_proto != nil {
|
||||
return
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_common_log_log_proto_rawDesc,
|
||||
NumEnums: 1,
|
||||
NumMessages: 0,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_common_log_log_proto_goTypes,
|
||||
DependencyIndexes: file_common_log_log_proto_depIdxs,
|
||||
EnumInfos: file_common_log_log_proto_enumTypes,
|
||||
}.Build()
|
||||
File_common_log_log_proto = out.File
|
||||
file_common_log_log_proto_rawDesc = nil
|
||||
file_common_log_log_proto_goTypes = nil
|
||||
file_common_log_log_proto_depIdxs = nil
|
||||
}
|
15
common/log/log.proto
Normal file
15
common/log/log.proto
Normal file
|
@ -0,0 +1,15 @@
|
|||
syntax = "proto3";
|
||||
|
||||
package xray.common.log;
|
||||
option csharp_namespace = "Xray.Common.Log";
|
||||
option go_package = "github.com/xtls/xray-core/v1/common/log";
|
||||
option java_package = "com.xray.common.log";
|
||||
option java_multiple_files = true;
|
||||
|
||||
enum Severity {
|
||||
Unknown = 0;
|
||||
Error = 1;
|
||||
Warning = 2;
|
||||
Info = 3;
|
||||
Debug = 4;
|
||||
}
|
33
common/log/log_test.go
Normal file
33
common/log/log_test.go
Normal file
|
@ -0,0 +1,33 @@
|
|||
package log_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
|
||||
"github.com/xtls/xray-core/v1/common/log"
|
||||
"github.com/xtls/xray-core/v1/common/net"
|
||||
)
|
||||
|
||||
type testLogger struct {
|
||||
value string
|
||||
}
|
||||
|
||||
func (l *testLogger) Handle(msg log.Message) {
|
||||
l.value = msg.String()
|
||||
}
|
||||
|
||||
func TestLogRecord(t *testing.T) {
|
||||
var logger testLogger
|
||||
log.RegisterHandler(&logger)
|
||||
|
||||
ip := "8.8.8.8"
|
||||
log.Record(&log.GeneralMessage{
|
||||
Severity: log.Severity_Error,
|
||||
Content: net.ParseAddress(ip),
|
||||
})
|
||||
|
||||
if diff := cmp.Diff("[Error] "+ip, logger.value); diff != "" {
|
||||
t.Error(diff)
|
||||
}
|
||||
}
|
152
common/log/logger.go
Normal file
152
common/log/logger.go
Normal file
|
@ -0,0 +1,152 @@
|
|||
package log
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/xtls/xray-core/v1/common/platform"
|
||||
"github.com/xtls/xray-core/v1/common/signal/done"
|
||||
"github.com/xtls/xray-core/v1/common/signal/semaphore"
|
||||
)
|
||||
|
||||
// Writer is the interface for writing logs.
|
||||
type Writer interface {
|
||||
Write(string) error
|
||||
io.Closer
|
||||
}
|
||||
|
||||
// WriterCreator is a function to create LogWriters.
|
||||
type WriterCreator func() Writer
|
||||
|
||||
type generalLogger struct {
|
||||
creator WriterCreator
|
||||
buffer chan Message
|
||||
access *semaphore.Instance
|
||||
done *done.Instance
|
||||
}
|
||||
|
||||
// NewLogger returns a generic log handler that can handle all type of messages.
|
||||
func NewLogger(logWriterCreator WriterCreator) Handler {
|
||||
return &generalLogger{
|
||||
creator: logWriterCreator,
|
||||
buffer: make(chan Message, 16),
|
||||
access: semaphore.New(1),
|
||||
done: done.New(),
|
||||
}
|
||||
}
|
||||
|
||||
func (l *generalLogger) run() {
|
||||
defer l.access.Signal()
|
||||
|
||||
dataWritten := false
|
||||
ticker := time.NewTicker(time.Minute)
|
||||
defer ticker.Stop()
|
||||
|
||||
logger := l.creator()
|
||||
if logger == nil {
|
||||
return
|
||||
}
|
||||
defer logger.Close()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-l.done.Wait():
|
||||
return
|
||||
case msg := <-l.buffer:
|
||||
logger.Write(msg.String() + platform.LineSeparator())
|
||||
dataWritten = true
|
||||
case <-ticker.C:
|
||||
if !dataWritten {
|
||||
return
|
||||
}
|
||||
dataWritten = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (l *generalLogger) Handle(msg Message) {
|
||||
select {
|
||||
case l.buffer <- msg:
|
||||
default:
|
||||
}
|
||||
|
||||
select {
|
||||
case <-l.access.Wait():
|
||||
go l.run()
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
func (l *generalLogger) Close() error {
|
||||
return l.done.Close()
|
||||
}
|
||||
|
||||
type consoleLogWriter struct {
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
func (w *consoleLogWriter) Write(s string) error {
|
||||
w.logger.Print(s)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *consoleLogWriter) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type fileLogWriter struct {
|
||||
file *os.File
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
func (w *fileLogWriter) Write(s string) error {
|
||||
w.logger.Print(s)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *fileLogWriter) Close() error {
|
||||
return w.file.Close()
|
||||
}
|
||||
|
||||
// CreateStdoutLogWriter returns a LogWriterCreator that creates LogWriter for stdout.
|
||||
func CreateStdoutLogWriter() WriterCreator {
|
||||
return func() Writer {
|
||||
return &consoleLogWriter{
|
||||
logger: log.New(os.Stdout, "", log.Ldate|log.Ltime),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CreateStderrLogWriter returns a LogWriterCreator that creates LogWriter for stderr.
|
||||
func CreateStderrLogWriter() WriterCreator {
|
||||
return func() Writer {
|
||||
return &consoleLogWriter{
|
||||
logger: log.New(os.Stderr, "", log.Ldate|log.Ltime),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CreateFileLogWriter returns a LogWriterCreator that creates LogWriter for the given file.
|
||||
func CreateFileLogWriter(path string) (WriterCreator, error) {
|
||||
file, err := os.OpenFile(path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
file.Close()
|
||||
return func() Writer {
|
||||
file, err := os.OpenFile(path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return &fileLogWriter{
|
||||
file: file,
|
||||
logger: log.New(file, "", log.Ldate|log.Ltime),
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
RegisterHandler(NewLogger(CreateStdoutLogWriter()))
|
||||
}
|
39
common/log/logger_test.go
Normal file
39
common/log/logger_test.go
Normal file
|
@ -0,0 +1,39 @@
|
|||
package log_test
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/xtls/xray-core/v1/common"
|
||||
"github.com/xtls/xray-core/v1/common/buf"
|
||||
. "github.com/xtls/xray-core/v1/common/log"
|
||||
)
|
||||
|
||||
func TestFileLogger(t *testing.T) {
|
||||
f, err := ioutil.TempFile("", "vtest")
|
||||
common.Must(err)
|
||||
path := f.Name()
|
||||
common.Must(f.Close())
|
||||
|
||||
creator, err := CreateFileLogWriter(path)
|
||||
common.Must(err)
|
||||
|
||||
handler := NewLogger(creator)
|
||||
handler.Handle(&GeneralMessage{Content: "Test Log"})
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
common.Must(common.Close(handler))
|
||||
|
||||
f, err = os.Open(path)
|
||||
common.Must(err)
|
||||
defer f.Close()
|
||||
|
||||
b, err := buf.ReadAllToBytes(f)
|
||||
common.Must(err)
|
||||
if !strings.Contains(string(b), "Test Log") {
|
||||
t.Fatal("Expect log text contains 'Test Log', but actually: ", string(b))
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue