Skip to content

Commit 16579ad

Browse files
committed
feat: new CallContext.{GetFuncName, GetPackageName} APIs
1 parent 4b4adf1 commit 16579ad

File tree

7 files changed

+116
-21
lines changed

7 files changed

+116
-21
lines changed

Diff for: pkg/api/api.go

+4
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,8 @@ type CallContext interface {
4646
GetReturnVal(idx int) interface{}
4747
// Change the original function return value at index idx
4848
SetReturnVal(idx int, val interface{})
49+
// Get the original function name
50+
GetFuncName() string
51+
// Get the package name of the original function
52+
GetPackageName() string
4953
}

Diff for: pkg/api/impl.go

+8
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,14 @@ func (c *CallContextImpl) SetReturnVal(idx int, val interface{}) {
6363
c.ReturnVals[idx] = val
6464
}
6565

66+
func (c *CallContextImpl) GetFuncName() string {
67+
return ""
68+
}
69+
70+
func (c *CallContextImpl) GetPackageName() string {
71+
return ""
72+
}
73+
6674
func NewCallContext() CallContext {
6775
return &CallContextImpl{
6876
Params: make([]interface{}, 1024),

Diff for: pkg/data/test_error.json

+7
Original file line numberDiff line numberDiff line change
@@ -138,5 +138,12 @@
138138
"Function": ".*",
139139
"OnEnter": "onEnterGeneric4",
140140
"Path": "github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/rules/test/error19"
141+
},
142+
{
143+
"ImportPath": "errorstest/all",
144+
"ReceiverType": ".*",
145+
"Function": ".*",
146+
"OnEnter": "onEnterGeneric5",
147+
"Path": "github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/rules/test/error19"
141148
}
142149
]

Diff for: pkg/rules/test/error19/hook.go

+5
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,8 @@ func onEnterGeneric3(call api.CallContext) {
3636
func onEnterGeneric4(call api.CallContext) {
3737
println("beijing")
3838
}
39+
40+
func onEnterGeneric5(call api.CallContext) {
41+
println("entering" + call.GetFuncName())
42+
println("within" + call.GetPackageName())
43+
}

Diff for: test/errors_test.go

+13-2
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ func TestRunErrors(t *testing.T) {
5858
}
5959

6060
// Test for generic hook
61+
maxFunc := 7
6162
re = regexp.MustCompile(".*xian.*")
6263
matches = re.FindAllString(stderr, -1)
6364
if len(matches) != 4 { // f1 + f2 + f4 + init
@@ -70,12 +71,22 @@ func TestRunErrors(t *testing.T) {
7071
}
7172
re = regexp.MustCompile(".*zhejiang.*") // match all funcs(including init)
7273
matches = re.FindAllString(stderr, -1)
73-
if len(matches) != 7 {
74-
t.Fatalf("expecting 7 matches")
74+
if len(matches) != maxFunc {
75+
t.Fatalf("expecting full matches")
7576
}
7677
re = regexp.MustCompile(".*beijing.*") // f3 + f5
7778
matches = re.FindAllString(stderr, -1)
7879
if len(matches) != 2 {
7980
t.Fatalf("expecting 2 matches")
8081
}
82+
re = regexp.MustCompile(".*entering.*") // match all funcs(including init)
83+
matches = re.FindAllString(stderr, -1)
84+
if len(matches) != maxFunc {
85+
t.Fatalf("expecting full matches")
86+
}
87+
re = regexp.MustCompile(".*within.*") // match all funcs(including init)
88+
matches = re.FindAllString(stderr, -1)
89+
if len(matches) != maxFunc {
90+
t.Fatalf("expecting full matches")
91+
}
8192
}

Diff for: tool/instrument/template.go

+11-4
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,12 @@ package instrument
2121

2222
// Struct Template
2323
type CallContextImpl struct {
24-
Params []interface{}
25-
ReturnVals []interface{}
26-
SkipCall bool
27-
Data interface{}
24+
Params []interface{}
25+
ReturnVals []interface{}
26+
SkipCall bool
27+
Data interface{}
28+
FuncName string
29+
PackageName string
2830
}
2931

3032
func (c *CallContextImpl) SetSkipCall(skip bool) { c.SkipCall = skip }
@@ -79,6 +81,9 @@ func (c *CallContextImpl) SetReturnVal(idx int, val interface{}) {
7981
}
8082
}
8183

84+
func (c *CallContextImpl) GetFuncName() string { return c.FuncName }
85+
func (c *CallContextImpl) GetPackageName() string { return c.PackageName }
86+
8287
// Variable Template
8388
var OtelGetStackImpl func() []byte = nil
8489
var OtelPrintStackImpl func([]byte) = nil
@@ -99,6 +104,8 @@ func OtelOnEnterTrampoline() (CallContext, bool) {
99104
}()
100105
callContext := &CallContextImpl{}
101106
callContext.Params = []interface{}{}
107+
callContext.FuncName = ""
108+
callContext.PackageName = ""
102109
return callContext, callContext.SkipCall
103110
}
104111

Diff for: tool/instrument/trampoline.go

+68-15
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ const (
4444
TrampolineValIdentifier = "val"
4545
TrampolineCtxIdentifier = "c"
4646
TrampolineParamsIdentifier = "Params"
47+
TrampolineFuncNameIdentifier = "FuncName"
48+
TrampolinePackageNameIdentifier = "PackageName"
4749
TrampolineReturnValsIdentifier = "ReturnVals"
4850
TrampolineSkipName = "skip"
4951
TrampolineCallContextName = "callContext"
@@ -400,34 +402,85 @@ func (rp *RuleProcessor) rectifyTypes() {
400402
addCallContext(onExitHookFunc.Type.Params)
401403
}
402404

405+
// replenishCallContext replenishes the call context before hook invocation
403406
func (rp *RuleProcessor) replenishCallContext(onEnter bool) bool {
404407
funcDecl := rp.onEnterHookFunc
405408
if !onEnter {
406409
funcDecl = rp.onExitHookFunc
407410
}
408411
for _, stmt := range funcDecl.Body.List {
409412
if assignStmt, ok := stmt.(*dst.AssignStmt); ok {
410-
rhs := assignStmt.Rhs
411-
if len(rhs) == 1 {
412-
rhsExpr := rhs[0]
413-
if compositeLit, ok := rhsExpr.(*dst.CompositeLit); ok {
414-
elems := compositeLit.Elts
415-
names := getNames(funcDecl.Type.Params)
416-
for i, name := range names {
417-
if i == 0 && !onEnter {
418-
// SKip first callContext parameter for onExit
419-
continue
413+
lhs := assignStmt.Lhs
414+
if sel, ok := lhs[0].(*dst.SelectorExpr); ok {
415+
switch sel.Sel.Name {
416+
case TrampolineFuncNameIdentifier:
417+
util.Assert(onEnter, "sanity check")
418+
// callContext.FuncName = "..."
419+
rhs := assignStmt.Rhs
420+
if len(rhs) == 1 {
421+
rhsExpr := rhs[0]
422+
if basicLit, ok := rhsExpr.(*dst.BasicLit); ok {
423+
if basicLit.Kind == token.STRING {
424+
rawFuncName := rp.rawFunc.Name.Name
425+
basicLit.Value = strconv.Quote(rawFuncName)
426+
} else {
427+
return false // ill-formed AST
428+
}
429+
} else {
430+
return false // ill-formed AST
431+
}
432+
} else {
433+
return false // ill-formed AST
434+
}
435+
dst.Print(rhs)
436+
case TrampolinePackageNameIdentifier:
437+
util.Assert(onEnter, "sanity check")
438+
// callContext.PackageName = "..."
439+
rhs := assignStmt.Rhs
440+
if len(rhs) == 1 {
441+
rhsExpr := rhs[0]
442+
if basicLit, ok := rhsExpr.(*dst.BasicLit); ok {
443+
if basicLit.Kind == token.STRING {
444+
pkgName := rp.target.Name.Name
445+
basicLit.Value = strconv.Quote(pkgName)
446+
} else {
447+
return false // ill-formed AST
448+
}
449+
} else {
450+
return false // ill-formed AST
420451
}
421-
elems = append(elems, util.Ident(name))
452+
} else {
453+
return false // ill-formed AST
454+
}
455+
default:
456+
// callContext.Params = []interface{}{...} or
457+
// callContext.(*CallContextImpl).Params[0] = &int
458+
rhs := assignStmt.Rhs
459+
if len(rhs) == 1 {
460+
rhsExpr := rhs[0]
461+
if compositeLit, ok := rhsExpr.(*dst.CompositeLit); ok {
462+
elems := compositeLit.Elts
463+
names := getNames(funcDecl.Type.Params)
464+
for i, name := range names {
465+
if i == 0 && !onEnter {
466+
// SKip first callContext parameter for onExit
467+
continue
468+
}
469+
elems = append(elems, util.Ident(name))
470+
}
471+
compositeLit.Elts = elems
472+
} else {
473+
return false // ill-formed AST
474+
}
475+
} else {
476+
return false // ill-formed AST
422477
}
423-
compositeLit.Elts = elems
424-
return true
425478
}
426479
}
480+
427481
}
428482
}
429-
util.ShouldNotReachHereT("failed to replenish call context")
430-
return false
483+
return true
431484
}
432485

433486
// -----------------------------------------------------------------------------

0 commit comments

Comments
 (0)