github.com/alibaba/ilogtail/pkg@v0.0.0-20250526110833-c53b480d046c/protocol/decoder/pyroscope/decoder_test.go (about) 1 // Copyright 2023 iLogtail Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package pyroscope 16 17 import ( 18 "bytes" 19 "encoding/binary" 20 "encoding/json" 21 "net/http" 22 "os" 23 "sort" 24 "testing" 25 26 "github.com/alibaba/ilogtail/pkg/helper" 27 "github.com/alibaba/ilogtail/pkg/protocol" 28 29 "github.com/pyroscope-io/pyroscope/pkg/structs/transporttrie" 30 "github.com/stretchr/testify/assert" 31 "github.com/stretchr/testify/require" 32 ) 33 34 func TestDecoder_DecodeTire(t *testing.T) { 35 36 type value struct { 37 k string 38 v uint64 39 } 40 values := []value{ 41 {"foo;bar;baz", 1}, 42 {"foo;bar;baz;a", 1}, 43 {"foo;bar;baz;b", 1}, 44 {"foo;bar;baz;c", 1}, 45 46 {"foo;bar;bar", 1}, 47 48 {"foo;bar;qux", 1}, 49 50 {"foo;bax;bar", 1}, 51 52 {"zoo;boo", 1}, 53 {"zoo;bao", 1}, 54 } 55 56 trie := transporttrie.New() 57 for _, v := range values { 58 trie.Insert([]byte(v.k), v.v) 59 } 60 var buf bytes.Buffer 61 trie.Serialize(&buf) 62 println(buf.String()) 63 request, err := http.NewRequest("POST", "http://localhost:8080?aggregationType=sum&from=1673495500&name=demo.cpu{a=b}&sampleRate=100&spyName=ebpfspy&units=samples&until=1673495510", &buf) 64 request.Header.Set("Content-Type", "binary/octet-stream+trie") 65 assert.NoError(t, err) 66 d := new(Decoder) 67 logs, err := d.Decode(buf.Bytes(), request, map[string]string{"cluster": "sls-mall"}) 68 assert.NoError(t, err) 69 assert.True(t, len(logs) == 9) 70 log := logs[1] 71 require.Equal(t, ReadLogVal(log, "name"), "baz") 72 require.Equal(t, ReadLogVal(log, "stack"), "bar\nfoo") 73 require.Equal(t, ReadLogVal(log, "language"), "ebpf") 74 require.Equal(t, ReadLogVal(log, "type"), "profile_cpu") 75 require.Equal(t, ReadLogVal(log, "units"), "nanoseconds") 76 require.Equal(t, ReadLogVal(log, "valueTypes"), "cpu") 77 require.Equal(t, ReadLogVal(log, "aggTypes"), "sum") 78 require.Equal(t, ReadLogVal(log, "dataType"), "CallStack") 79 require.Equal(t, ReadLogVal(log, "durationNs"), "10000000000") 80 require.Equal(t, ReadLogVal(log, "labels"), "{\"__name__\":\"demo\",\"a\":\"b\",\"cluster\":\"sls-mall\"}") 81 require.Equal(t, ReadLogVal(log, "val"), "10000000.00") 82 } 83 84 func TestDecoder_DecodePprofCumulative(t *testing.T) { 85 data, err := os.ReadFile("test/dump_pprof_mem_data") 86 require.NoError(t, err) 87 var length uint32 88 buffer := bytes.NewBuffer(data) 89 require.NoError(t, binary.Read(buffer, binary.BigEndian, &length)) 90 data = data[4 : 4+int(length)] 91 var d helper.DumpData 92 require.NoError(t, json.Unmarshal(data, &d)) 93 request, err := http.NewRequest("POST", d.Req.URL, bytes.NewReader(d.Req.Body)) 94 require.NoError(t, err) 95 request.Header = d.Req.Header 96 dec := new(Decoder) 97 logs, err := dec.Decode(d.Req.Body, request, map[string]string{"cluster": "sls-mall"}) 98 require.NoError(t, err) 99 require.Equal(t, len(logs), 4) 100 sort.Slice(logs, func(i, j int) bool { 101 if ReadLogVal(logs[i], "name") < ReadLogVal(logs[j], "name") { 102 return true 103 } else if ReadLogVal(logs[i], "name") == ReadLogVal(logs[j], "name") { 104 return ReadLogVal(logs[i], "valueTypes") < ReadLogVal(logs[j], "valueTypes") 105 } 106 return false 107 }) 108 require.Equal(t, ReadLogVal(logs[0], "name"), "compress/flate.NewWriter /Users/evan/sdk/go1.19.4/src/compress/flate/deflate.go") 109 require.Equal(t, ReadLogVal(logs[0], "valueTypes"), "alloc_objects") 110 require.Equal(t, ReadLogVal(logs[0], "val"), "1.00") 111 112 require.Equal(t, ReadLogVal(logs[1], "name"), "compress/flate.NewWriter /Users/evan/sdk/go1.19.4/src/compress/flate/deflate.go") 113 require.Equal(t, ReadLogVal(logs[1], "valueTypes"), "alloc_space") 114 require.Equal(t, ReadLogVal(logs[1], "val"), "924248.00") 115 116 require.Equal(t, ReadLogVal(logs[2], "name"), "runtime/pprof.WithLabels /Users/evan/sdk/go1.19.4/src/runtime/pprof/label.go") 117 require.Equal(t, ReadLogVal(logs[2], "valueTypes"), "alloc_objects") 118 require.Equal(t, ReadLogVal(logs[2], "val"), "1820.00") 119 120 require.Equal(t, ReadLogVal(logs[3], "name"), "runtime/pprof.WithLabels /Users/evan/sdk/go1.19.4/src/runtime/pprof/label.go") 121 require.Equal(t, ReadLogVal(logs[3], "valueTypes"), "alloc_space") 122 require.Equal(t, ReadLogVal(logs[3], "val"), "524432.00") 123 } 124 125 // ReadLogVal returns the log content value for the input key, and returns empty string when not found. 126 func ReadLogVal(log *protocol.Log, key string) string { 127 for _, content := range log.Contents { 128 if content.Key == key { 129 return content.Value 130 } 131 } 132 return "" 133 }