-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcontext.go
145 lines (122 loc) · 2.83 KB
/
context.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package slog
import (
"context"
"log/slog"
"sync"
"time"
)
// contextKey 定义上下文键
type contextKey string
const (
fieldsKey contextKey = "slog_fields"
)
// Fields 存储上下文字段
type Fields struct {
values map[string]interface{}
mu sync.RWMutex
}
// fieldsPool 对象池
var fieldsPool = sync.Pool{
New: func() interface{} {
return &Fields{
values: make(map[string]interface{}),
}
},
}
// newFields 创建新的Fields实例
func newFields() *Fields {
return fieldsPool.Get().(*Fields)
}
// release 释放Fields实例
func (f *Fields) release() {
f.mu.Lock()
clear(f.values)
f.mu.Unlock()
fieldsPool.Put(f)
}
// clone 克隆Fields实例
func (f *Fields) clone() *Fields {
newF := newFields()
if f != nil {
f.mu.RLock()
for k, v := range f.values {
newF.values[k] = v
}
f.mu.RUnlock()
}
return newF
}
// getFields 从上下文中获取Fields
func getFields(ctx context.Context) *Fields {
if ctx == nil {
return nil
}
if f, ok := ctx.Value(fieldsKey).(*Fields); ok {
return f
}
return nil
}
// WithContext 创建带有上下文的新Logger
func (l *Logger) WithContext(ctx context.Context) *Logger {
if ctx == nil {
return l
}
newLogger := l.clone()
newLogger.ctx = ctx
// 监听context取消
go func() {
<-ctx.Done()
if fields := getFields(ctx); fields != nil {
fields.release()
}
}()
// 更新handlers的context
if newLogger.text != nil {
newLogger.text = slog.New(newAddonsHandler(newLogger.text.Handler(), ext))
}
if newLogger.json != nil {
newLogger.json = slog.New(newAddonsHandler(newLogger.json.Handler(), ext))
}
return newLogger
}
// WithValue 在上下文中存储一个键值对,并返回新的上下文
func (l *Logger) WithValue(key string, val interface{}) *Logger {
if key == "" || val == nil {
return l
}
newLogger := l.clone()
if newLogger.ctx == nil {
newLogger.ctx = context.Background()
}
// 创建新的Fields或克隆现有的
var newFields *Fields
if oldFields := getFields(newLogger.ctx); oldFields != nil {
newFields = oldFields.clone()
} else {
newFields = fieldsPool.Get().(*Fields)
}
// 添加新值
newFields.mu.Lock()
newFields.values[key] = val
newFields.mu.Unlock()
// 创建新的context
ctx, cancel := context.WithCancel(newLogger.ctx)
newLogger.ctx = context.WithValue(ctx, fieldsKey, newFields)
// 监听context取消
go func() {
<-ctx.Done()
newFields.release()
cancel()
}()
return newLogger
}
// WithTimeout 创建带超时的Logger
func (l *Logger) WithTimeout(timeout time.Duration) (*Logger, context.CancelFunc) {
ctx, cancel := context.WithTimeout(l.ctx, timeout)
return l.WithContext(ctx), cancel
}
// WithDeadline 创建带截止时间的Logger
func (l *Logger) WithDeadline(d time.Time) (*Logger, context.CancelFunc) {
ctx, cancel := context.WithDeadline(l.ctx, d)
return l.WithContext(ctx), cancel
}