-
Notifications
You must be signed in to change notification settings - Fork 0
/
aop.go
173 lines (141 loc) · 3.88 KB
/
aop.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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
package do
import (
"context"
"fmt"
"log"
"strings"
"time"
)
// 每个包、每个接口、每个方法唯一对应一个方法
type ProxyContext struct {
PkgPath string
InterfaceName string
MethodName string
}
func (pctx ProxyContext) String() string {
return fmt.Sprintf(pctx.bracket("PkgPath: %s InterfaceName: %s MethodName: %s"), pctx.PkgPath, pctx.InterfaceName, pctx.MethodName)
}
func (pctx ProxyContext) Uniq() string {
return pctx.PkgPath + "|" + pctx.InterfaceName + "|" + pctx.MethodName
}
func (pctx ProxyContext) IsEmpty() bool {
return pctx.PkgPath == "" && pctx.InterfaceName == "" && pctx.MethodName == ""
}
func (pctx ProxyContext) Logf(format string, args ...any) {
pctx.logf(pctx.String()+": "+format, args...)
}
func (pctx ProxyContext) LogShortf(format string, args ...any) {
pctx.logf(pctx.bracket(pctx.MethodName)+": "+format, args...)
}
func (pctx ProxyContext) logf(format string, args ...any) {
err := log.Output(3, fmt.Sprintf(format, args...))
if err != nil {
fmt.Printf("Output failed: %+v\n", err)
}
}
func (pctx ProxyContext) bracket(s string) string {
return "[" + s + "]"
}
// ProxyCtxFunc
// 对于method: func(string, int) (int, error)
// f := method.(func(string, int) (int, error))
// a1 := args[0].(string)
// a2 := args[1].(int)
// r1, r2 := f(a1, a2)
// res = append(res, r1, r2)
type ProxyCtxFunc func(ctx ProxyContext, method any, args []any) (res []any)
type ProxyCtxFuncStore struct {
m map[string]ProxyCtxFunc
}
func NewProxyCtxMap() *ProxyCtxFuncStore {
return &ProxyCtxFuncStore{
m: make(map[string]ProxyCtxFunc),
}
}
func (m *ProxyCtxFuncStore) Lookup(pctx ProxyContext, typeParams ...string) (ProxyCtxFunc, bool) {
key := pctxUniqWithTypeParams(pctx.Uniq(), typeParams...)
v, ok := m.m[key]
return v, ok
}
func (m *ProxyCtxFuncStore) Set(pctx ProxyContext, f ProxyCtxFunc, typeParams ...string) {
key := pctxUniqWithTypeParams(pctx.Uniq(), typeParams...)
m.m[key] = f
}
func pctxUniqWithTypeParams(uniq string, typeParams ...string) string {
if len(typeParams) > 0 {
uniq = uniq + "|" + strings.Join(typeParams, ",")
}
return uniq
}
var (
globalProxyCtxMap = NewProxyCtxMap()
)
// RegisterProxyMethod 注册代理方法,根据包名+接口名+方法名唯一对应一个方法;在有了泛型后还要加上类型参数,唯一键变为包名+接口名+方法名+TP1,TP2,...
func RegisterProxyMethod(pctx ProxyContext, cf ProxyCtxFunc, typeParams ...string) {
globalProxyCtxMap.Set(pctx, cf, typeParams...)
}
func GlobalProxyCtxMap() *ProxyCtxFuncStore {
return globalProxyCtxMap
}
type Tracer interface {
New(pctx ProxyContext, extras ...any) Tracer // 新建Tracer,每个方法调用均新建一个
Begin()
Stop()
}
type tracers []Tracer
var (
gtracers = tracers{
&TimeTracer{},
}
)
func RegisterProxyTracer(tracers ...Tracer) {
gtracers = append(gtracers, tracers...)
}
// ProxyTraceBegin LIFO
func ProxyTraceBegin(pctx ProxyContext, extras ...any) (stop func()) {
stops := make([]func(), 0, len(gtracers))
for _, tc := range gtracers {
o := tc.New(pctx, extras...)
o.Begin()
stops = append(stops, o.Stop)
}
stop = func() {
for i := len(stops) - 1; i >= 0; i-- {
so := stops[i]
so()
}
}
return
}
type TimeTracer struct {
pctx ProxyContext
traceId string
begin time.Time
}
type TraceKey struct{}
func (impl *TimeTracer) New(pctx ProxyContext, extras ...any) Tracer {
traceId := parseExtra(extras...)
return &TimeTracer{
pctx: pctx,
traceId: traceId,
}
}
func (impl *TimeTracer) Begin() {
impl.begin = time.Now()
}
func (impl *TimeTracer) Stop() {
log.Output(3, fmt.Sprintf("[%s] |%s| used time %v\n", impl.pctx, impl.traceId, time.Since(impl.begin)))
}
func parseExtra(extras ...any) (traceId string) {
if len(extras) == 0 {
return
}
ctx, ok := extras[0].(context.Context)
if ok {
v := ctx.Value(TraceKey{})
if vv, ok := v.(string); ok {
traceId = vv
}
}
return
}