github.com/waldiirawan/apm-agent-go/v2@v2.2.2/stacktrace/stacktrace_test.go (about) 1 // Licensed to Elasticsearch B.V. under one or more contributor 2 // license agreements. See the NOTICE file distributed with 3 // this work for additional information regarding copyright 4 // ownership. Elasticsearch B.V. licenses this file to you under 5 // the Apache License, Version 2.0 (the "License"); you may 6 // not use this file except in compliance with the License. 7 // You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, 12 // software distributed under the License is distributed on an 13 // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 // KIND, either express or implied. See the License for the 15 // specific language governing permissions and limitations 16 // under the License. 17 18 package stacktrace_test 19 20 import ( 21 "testing" 22 23 "github.com/google/go-cmp/cmp" 24 "github.com/stretchr/testify/require" 25 26 "github.com/waldiirawan/apm-agent-go/v2/stacktrace" 27 ) 28 29 func TestStacktrace(t *testing.T) { 30 expect := []string{ 31 "github.com/waldiirawan/apm-agent-go/v2/stacktrace_test.callPanickerDefer", 32 "runtime.gopanic", 33 "github.com/waldiirawan/apm-agent-go/v2/stacktrace_test.(*panicker).panic", 34 "github.com/waldiirawan/apm-agent-go/v2/stacktrace_test.callPanicker", 35 } 36 37 ch := make(chan []string) 38 go callPanicker(ch) 39 functions := <-ch 40 require.NotNil(t, functions) 41 if diff := cmp.Diff(expect, functions); diff != "" { 42 t.Fatalf("%s", diff) 43 } 44 } 45 46 func callPanicker(ch chan<- []string) { 47 defer callPanickerDefer(ch) 48 (&panicker{}).panic() 49 } 50 51 func callPanickerDefer(ch chan<- []string) { 52 if recover() == nil { 53 ch <- nil 54 return 55 } 56 allFrames := stacktrace.AppendStacktrace(nil, 1, 5) 57 functions := make([]string, 0, len(allFrames)) 58 for _, frame := range allFrames { 59 switch frame.Function { 60 case "runtime.call32", "runtime.goexit": 61 // Depending on the Go toolchain version, these may or may not be present. 62 default: 63 functions = append(functions, frame.Function) 64 } 65 } 66 ch <- functions 67 } 68 69 type panicker struct{} 70 71 func (*panicker) panic() { 72 panic("oh noes") 73 } 74 75 func TestSplitFunctionName(t *testing.T) { 76 testSplitFunctionName(t, "main", "main") 77 testSplitFunctionName(t, "main", "Foo.Bar") 78 testSplitFunctionName(t, "main", "(*Foo).Bar") 79 testSplitFunctionName(t, "github.com/waldiirawan/apm-agent-go/v2/foo", "bar") 80 testSplitFunctionName(t, 81 "github.com/waldiirawan/apm-agent-go/module/apmgin/v2", 82 "(*middleware).(github.com/waldiirawan/apm-agent-go/module/apmgin.handle)-fm", 83 ) 84 } 85 86 func testSplitFunctionName(t *testing.T, module, function string) { 87 outModule, outFunction := stacktrace.SplitFunctionName(module + "." + function) 88 assertModule(t, outModule, module) 89 assertFunction(t, outFunction, function) 90 } 91 92 func TestSplitFunctionNameUnescape(t *testing.T) { 93 module, function := stacktrace.SplitFunctionName("github.com/elastic/apm-agent%2ego.funcName") 94 assertModule(t, module, "github.com/elastic/apm-agent.go") 95 assertFunction(t, function, "funcName") 96 97 // malformed escape sequences are left alone 98 module, function = stacktrace.SplitFunctionName("github.com/elastic/apm-agent%.funcName") 99 assertModule(t, module, "github.com/elastic/apm-agent%") 100 assertFunction(t, function, "funcName") 101 } 102 103 func assertModule(t *testing.T, got, expect string) { 104 if got != expect { 105 t.Errorf("got module %q, expected %q", got, expect) 106 } 107 } 108 109 func assertFunction(t *testing.T, got, expect string) { 110 if got != expect { 111 t.Errorf("got function %q, expected %q", got, expect) 112 } 113 } 114 115 func BenchmarkAppendStacktraceUnlimited(b *testing.B) { 116 var frames []stacktrace.Frame 117 for i := 0; i < b.N; i++ { 118 frames = stacktrace.AppendStacktrace(frames[:0], 0, -1) 119 } 120 } 121 122 func BenchmarkAppendStacktrace10(b *testing.B) { 123 var frames []stacktrace.Frame 124 for i := 0; i < b.N; i++ { 125 frames = stacktrace.AppendStacktrace(frames[:0], 0, 10) 126 } 127 } 128 129 func BenchmarkAppendStacktrace50(b *testing.B) { 130 var frames []stacktrace.Frame 131 for i := 0; i < b.N; i++ { 132 frames = stacktrace.AppendStacktrace(frames[:0], 0, 50) 133 } 134 }