Phlare: Switch to the new Pprof endpoint (#61505)

Co-authored-by: Joey Tawadrous <joey.tawadrous@grafana.com>
Co-authored-by: Andrej Ocenas <mr.ocenas@gmail.com>
This commit is contained in:
Cyril Tovena
2023-02-28 11:28:45 +01:00
committed by GitHub
parent 71d64f95da
commit dde9b22113
6 changed files with 1689 additions and 203 deletions

20
go.mod
View File

@@ -131,7 +131,7 @@ require (
gopkg.in/square/go-jose.v2 v2.5.1
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1
xorm.io/builder v0.3.6
xorm.io/builder v0.3.6 // indirect
xorm.io/core v0.7.3
xorm.io/xorm v0.8.2
)
@@ -254,7 +254,7 @@ require (
github.com/google/go-github/v45 v45.2.0
github.com/grafana/codejen v0.0.3
github.com/grafana/dskit v0.0.0-20230202092222-880a7f8141cc
github.com/grafana/phlare/api v0.1.2
github.com/grafana/phlare/api v0.1.3
github.com/huandu/xstrings v1.3.1
github.com/jmoiron/sqlx v1.3.5
github.com/matryer/is v1.4.0
@@ -274,6 +274,7 @@ require (
github.com/dave/dst v0.27.2
github.com/grafana/thema v0.0.0-20230221105543-a6a177d234d7
github.com/hmarr/codeowners v1.1.1
github.com/weaveworks/common v0.0.0-20230208133027-16871410fca4
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f
)
@@ -292,7 +293,7 @@ require (
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/digitalocean/godo v1.80.0 // indirect
github.com/digitalocean/godo v1.88.0 // indirect
github.com/dnaeon/go-vcr v1.2.0 // indirect
github.com/docker/distribution v2.8.1+incompatible // indirect
github.com/docker/go-connections v0.4.0 // indirect
@@ -300,21 +301,21 @@ require (
github.com/drone/drone-go v1.7.1 // indirect
github.com/drone/envsubst v1.0.3 // indirect
github.com/drone/runner-go v1.12.0 // indirect
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1 // indirect
github.com/envoyproxy/protoc-gen-validate v0.6.7 // indirect
github.com/envoyproxy/go-control-plane v0.10.3 // indirect
github.com/envoyproxy/protoc-gen-validate v0.6.13 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.2.0 // indirect
github.com/gophercloud/gophercloud v0.24.0 // indirect
github.com/gophercloud/gophercloud v1.0.0 // indirect
github.com/grafana/sqlds/v2 v2.3.10 // indirect
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.1 // indirect
github.com/hashicorp/memberlist v0.5.0 // indirect
github.com/hetznercloud/hcloud-go v1.33.2 // indirect
github.com/hetznercloud/hcloud-go v1.35.3 // indirect
github.com/invopop/yaml v0.1.0 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/linode/linodego v1.5.0 // indirect
github.com/linode/linodego v1.9.3 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-ieproxy v0.0.3 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
@@ -332,7 +333,6 @@ require (
github.com/unknwon/bra v0.0.0-20200517080246-1e3013ecaff8 // indirect
github.com/unknwon/com v1.0.1 // indirect
github.com/unknwon/log v0.0.0-20150304194804-e617c87089d3 // indirect
github.com/weaveworks/common v0.0.0-20230208133027-16871410fca4 // indirect
github.com/weaveworks/promrus v1.2.0 // indirect
go.opentelemetry.io/otel/metric v0.34.0 // indirect
go.starlark.net v0.0.0-20221020143700-22309ac47eac // indirect
@@ -393,7 +393,7 @@ require (
github.com/valyala/fasttemplate v1.2.2 // indirect
github.com/wk8/go-ordered-map v1.0.0
github.com/xanzy/ssh-agent v0.3.0 // indirect
github.com/xlab/treeprint v1.1.0 // indirect
github.com/xlab/treeprint v1.1.0
github.com/yudai/pp v2.0.1+incompatible // indirect
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.11.2 // indirect
go.opentelemetry.io/proto/otlp v0.19.0 // indirect

36
go.sum
View File

@@ -488,9 +488,9 @@ github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XP
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1 h1:zH8ljVhhq7yC0MIeUL/IviMtY8hx2mK8cN9wEYb8ggw=
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc h1:PYXxkRUBGUMa5xgMVMDl62vEklZvKpVaxQeN9ie7Hfk=
github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
github.com/cockroachdb/apd/v2 v2.0.2 h1:weh8u7Cneje73dDh+2tEVLUvyBc89iwepWCD8b8034E=
github.com/cockroachdb/apd/v2 v2.0.2/go.mod h1:DDxRlzC2lo3/vSlmSoS7JkqbbrARPuFOGr0B9pvN3Gw=
@@ -669,8 +669,8 @@ github.com/dgryski/go-sip13 v0.0.0-20200911182023-62edffca9245/go.mod h1:vAd38F8
github.com/dhui/dktest v0.3.0/go.mod h1:cyzIUfGsBEbZ6BT7tnXqAShHSXCZhSNmFl70sZ7c1yc=
github.com/digitalocean/godo v1.62.0/go.mod h1:p7dOjjtSBqCTUksqtA5Fd3uaKs9kyTq2xcz76ulEJRU=
github.com/digitalocean/godo v1.65.0/go.mod h1:p7dOjjtSBqCTUksqtA5Fd3uaKs9kyTq2xcz76ulEJRU=
github.com/digitalocean/godo v1.80.0 h1:ZULJ/fWDM97YtO7Fa+K6hzJLd7+smCu4N+0n+B/xtj4=
github.com/digitalocean/godo v1.80.0/go.mod h1:BPCqvwbjbGqxuUnIKB4EvS/AX7IDnNmt5fwvIkWo+ew=
github.com/digitalocean/godo v1.88.0 h1:SAEdw63xOMmzlwCeCWjLH1GcyDPUjbSAR1Bh7VELxzc=
github.com/digitalocean/godo v1.88.0/go.mod h1:NRpFznZFvhHjBoqZAaOD3khVzsJ3EibzKqFL4R60dmA=
github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8=
github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE=
github.com/dlmiddlecote/sqlstats v1.0.2 h1:gSU11YN23D/iY50A2zVYwgXgy072khatTsIW6UPjUtI=
@@ -737,12 +737,13 @@ github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
github.com/envoyproxy/go-control-plane v0.9.9/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1 h1:xvqufLtNVwAhN8NMyWklVgxnWohi+wtMGQMhtxexlm0=
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
github.com/envoyproxy/go-control-plane v0.10.3 h1:xdCVXxEe0Y3FQith+0cj2irwZudqGYvecuLB1HtdexY=
github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/envoyproxy/protoc-gen-validate v0.6.1/go.mod h1:txg5va2Qkip90uYoSKH+nkAAmXrb2j3iq4FLwdrCbXQ=
github.com/envoyproxy/protoc-gen-validate v0.6.7 h1:qcZcULcd/abmQg6dwigimCNEyi4gg31M/xaciQlDml8=
github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo=
github.com/envoyproxy/protoc-gen-validate v0.6.13 h1:TvDcILLkjuZV3ER58VkBmncKsLUBqBDxra/XctCzuMM=
github.com/envoyproxy/protoc-gen-validate v0.6.13/go.mod h1:qEySVqXrEugbHKvmhI8ZqtQi75/RHSSRNpffvB4I6Bw=
github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
@@ -1225,8 +1226,8 @@ github.com/gophercloud/gophercloud v0.3.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEo
github.com/gophercloud/gophercloud v0.10.0/go.mod h1:gmC5oQqMDOMO1t1gq5DquX/yAU808e/4mzjjDA76+Ss=
github.com/gophercloud/gophercloud v0.18.0/go.mod h1:wRtmUelyIIv3CSSDI47aUwbs075O6i+LY+pXsKCBsb4=
github.com/gophercloud/gophercloud v0.20.0/go.mod h1:wRtmUelyIIv3CSSDI47aUwbs075O6i+LY+pXsKCBsb4=
github.com/gophercloud/gophercloud v0.24.0 h1:jDsIMGJ1KZpAjYfQgGI2coNQj5Q83oPzuiGJRFWgMzw=
github.com/gophercloud/gophercloud v0.24.0/go.mod h1:Q8fZtyi5zZxPS/j9aj3sSxtvj41AdQMDwyo1myduD5c=
github.com/gophercloud/gophercloud v1.0.0 h1:9nTGx0jizmHxDobe4mck89FyQHVyA3CaXLIUSGJjP9k=
github.com/gophercloud/gophercloud v1.0.0/go.mod h1:Q8fZtyi5zZxPS/j9aj3sSxtvj41AdQMDwyo1myduD5c=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1ks85zJ1lfDGgIiMDuIptTOhJq+zKyg=
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
@@ -1268,8 +1269,8 @@ github.com/grafana/grafana-plugin-sdk-go v0.94.0/go.mod h1:3VXz4nCv6wH5SfgB3mlW3
github.com/grafana/grafana-plugin-sdk-go v0.114.0/go.mod h1:D7x3ah+1d4phNXpbnOaxa/osSaZlwh9/ZUnGGzegRbk=
github.com/grafana/grafana-plugin-sdk-go v0.149.1 h1:n4Mx8oUE+exa1DGdWSUmp2DuZUDhURQEzPG05HUGfnc=
github.com/grafana/grafana-plugin-sdk-go v0.149.1/go.mod h1:NMgO3t2gR5wyLx8bWZ9CTmpDk5Txp4wYFccFLHdYn3Q=
github.com/grafana/phlare/api v0.1.2 h1:1jrwd3KnsXMzj/tJih9likx5EvbY3pbvLbDqAAYem30=
github.com/grafana/phlare/api v0.1.2/go.mod h1:29vcLwFDmZBDce2jwFIMtzvof7fzPadT8VMKw9ks7FU=
github.com/grafana/phlare/api v0.1.3 h1:mYTaE9mLsAW/uzPXlW/PQSLsZ4ojBFA+oAMfR/PDdw8=
github.com/grafana/phlare/api v0.1.3/go.mod h1:29vcLwFDmZBDce2jwFIMtzvof7fzPadT8VMKw9ks7FU=
github.com/grafana/prometheus-alertmanager v0.25.1-0.20230119183635-ec19b0a443b7 h1:ma1CfisUaAXQzL24tCao9yMleZYsFJ853m2l0rgahyE=
github.com/grafana/prometheus-alertmanager v0.25.1-0.20230119183635-ec19b0a443b7/go.mod h1:MnBfDPXJqXmmfPwQlCLvVUdqfnvrAw+hSPtDeaaFwj4=
github.com/grafana/saml v0.4.13-0.20230203140620-5f476db5c00a h1:aWSTt/pTOI4uGY9DhBMG1l0GOnGjIYtaqxzYR3/q82o=
@@ -1394,8 +1395,8 @@ github.com/hashicorp/yamux v0.0.0-20210826001029-26ff87cf9493 h1:brI5vBRUlAlM34V
github.com/hashicorp/yamux v0.0.0-20210826001029-26ff87cf9493/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ=
github.com/hetznercloud/hcloud-go v1.26.2/go.mod h1:2C5uMtBiMoFr3m7lBFPf7wXTdh33CevmZpQIIDPGYJI=
github.com/hetznercloud/hcloud-go v1.32.0/go.mod h1:XX/TQub3ge0yWR2yHWmnDVIrB+MQbda1pHxkUmDlUME=
github.com/hetznercloud/hcloud-go v1.33.2 h1:ptWKVYLW7YtjXzsqTFKFxwpVo3iM9UMkVPBYQE4teLU=
github.com/hetznercloud/hcloud-go v1.33.2/go.mod h1:XX/TQub3ge0yWR2yHWmnDVIrB+MQbda1pHxkUmDlUME=
github.com/hetznercloud/hcloud-go v1.35.3 h1:WCmFAhLRooih2QHAsbCbEdpIHnshQQmrPqsr3rHE1Ow=
github.com/hetznercloud/hcloud-go v1.35.3/go.mod h1:mepQwR6va27S3UQthaEPGS86jtzSY9xWL1e9dyxXpgA=
github.com/hmarr/codeowners v1.1.1 h1:a1eD22I36JYH6O/zb+R+JkJgQ3CSlbu6H9EserOojSw=
github.com/hmarr/codeowners v1.1.1/go.mod h1:+ez+YARvfVhzL1MzY0f2+D/VusjODs4iRj3tO/IxBMw=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
@@ -1620,12 +1621,13 @@ github.com/linkedin/goavro/v2 v2.10.0 h1:eTBIRoInBM88gITGXYtUSqqxLTFXfOsJBiX8ZMW
github.com/linkedin/goavro/v2 v2.10.0/go.mod h1:UgQUb2N/pmueQYH9bfqFioWxzYCZXSfF8Jw03O5sjqA=
github.com/linode/linodego v0.28.5/go.mod h1:BR0gVkCJffEdIGJSl6bHR80Ty+Uvg/2jkjmrWaFectM=
github.com/linode/linodego v0.32.0/go.mod h1:BR0gVkCJffEdIGJSl6bHR80Ty+Uvg/2jkjmrWaFectM=
github.com/linode/linodego v1.5.0 h1:p1TgkDsz0ubaIPLNviZBTIjlsX3PdvqZQ4eO2r0L1Hk=
github.com/linode/linodego v1.5.0/go.mod h1:9lmhBsOupR6ke7D9Ioj1bq/ny9pfgFkCLiX7ubq0r08=
github.com/linode/linodego v1.9.3 h1:+lxNZw4avRxhCqGjwfPgQ2PvMT+vOL0OMsTdzixR7hQ=
github.com/linode/linodego v1.9.3/go.mod h1:h6AuFR/JpqwwM/vkj7s8KV3iGN8/jxn+zc437F8SZ8w=
github.com/lucasb-eyer/go-colorful v1.0.2/go.mod h1:0MS4r+7BZKSJ5mw4/S5MPN+qHFF1fYclkSPilDOKW0s=
github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/lyft/protoc-gen-star v0.5.1/go.mod h1:9toiA3cC7z5uVbODF7kEQ91Xn7XNFkVUl+SrEe+ZORU=
github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA=
github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA=
github.com/m3db/prometheus_remote_client_golang v0.4.4 h1:DsAIjVKoCp7Ym35tAOFL1OuMLIdIikAEHeNPHY+yyM8=
github.com/m3db/prometheus_remote_client_golang v0.4.4/go.mod h1:wHfVbA3eAK6dQvKjCkHhusWYegCk3bDGkA15zymSHdc=
github.com/magefile/mage v1.11.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
@@ -2127,6 +2129,7 @@ github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY52
github.com/spf13/afero v1.3.4/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo=
github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
@@ -2402,6 +2405,7 @@ go.opentelemetry.io/otel/trace v1.11.1/go.mod h1:f/Q9G7vzk5u91PhbmKbg1Qn0rzH1LJ4
go.opentelemetry.io/otel/trace v1.11.2 h1:Xf7hWSF2Glv0DE3MH7fBHvtpSBsjcBUe5MYAmZM/+y0=
go.opentelemetry.io/otel/trace v1.11.2/go.mod h1:4N+yC7QEz7TTsG9BSRLNAa63eg5E06ObSbKPmxQ/pKA=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
go.opentelemetry.io/proto/otlp v0.19.0 h1:IVN6GR+mhC4s5yfcTbmzHYODqvWAp3ZedA2SJPI1Nnw=
go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
go.starlark.net v0.0.0-20221020143700-22309ac47eac h1:gBO5Qfcw5V9404yzsu2FEIsxK/u2mBNTNogK0uIoVhk=
@@ -2644,6 +2648,7 @@ golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2/go.mod h1:CfG3xpIq0wQ8r1q4Su
golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220907135653-1e95f45603a7/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
@@ -2859,6 +2864,7 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908150016-7ac13a9a928d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=

View File

@@ -14,6 +14,9 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/data"
"github.com/grafana/grafana-plugin-sdk-go/live"
"github.com/grafana/grafana/pkg/tsdb/phlare/kinds/dataquery"
"github.com/xlab/treeprint"
googlev1 "github.com/grafana/phlare/api/gen/proto/go/google/v1"
querierv1 "github.com/grafana/phlare/api/gen/proto/go/querier/v1"
)
@@ -81,10 +84,10 @@ func (d *PhlareDatasource) query(ctx context.Context, pCtx backend.PluginContext
if query.QueryType == queryTypeProfile || query.QueryType == queryTypeBoth {
req := makeRequest(qm, query)
logger.Debug("Sending SelectMergeStacktracesRequest", "request", req, "queryModel", qm)
resp, err := d.client.SelectMergeStacktraces(ctx, makeRequest(qm, query))
logger.Debug("Sending SelectMergeProfile", "request", req, "queryModel", qm)
resp, err := d.client.SelectMergeProfile(ctx, req)
if err != nil {
logger.Error("Querying SelectMergeStacktraces()", "err", err)
logger.Error("Querying SelectMergeProfile()", "err", err)
response.Error = err
return response
}
@@ -107,9 +110,9 @@ func (d *PhlareDatasource) query(ctx context.Context, pCtx backend.PluginContext
return response
}
func makeRequest(qm queryModel, query backend.DataQuery) *connect.Request[querierv1.SelectMergeStacktracesRequest] {
return &connect.Request[querierv1.SelectMergeStacktracesRequest]{
Msg: &querierv1.SelectMergeStacktracesRequest{
func makeRequest(qm queryModel, query backend.DataQuery) *connect.Request[querierv1.SelectMergeProfileRequest] {
return &connect.Request[querierv1.SelectMergeProfileRequest]{
Msg: &querierv1.SelectMergeProfileRequest{
ProfileTypeID: qm.ProfileTypeId,
LabelSelector: qm.LabelSelector,
Start: query.TimeRange.From.UnixMilli(),
@@ -121,114 +124,180 @@ func makeRequest(qm queryModel, query backend.DataQuery) *connect.Request[querie
// responseToDataFrames turns Phlare response to data.Frame. We encode the data into a nested set format where we have
// [level, value, label] columns and by ordering the items in a depth first traversal order we can recreate the whole
// tree back.
func responseToDataFrames(resp *connect.Response[querierv1.SelectMergeStacktracesResponse], profileTypeID string) *data.Frame {
tree := levelsToTree(resp.Msg.Flamegraph.Levels, resp.Msg.Flamegraph.Names)
func responseToDataFrames(resp *connect.Response[googlev1.Profile], profileTypeID string) *data.Frame {
tree := profileAsTree(resp.Msg)
return treeToNestedSetDataFrame(tree, profileTypeID)
}
// START_OFFSET is offset of the bar relative to previous sibling
const START_OFFSET = 0
// VALUE_OFFSET is value or width of the bar
const VALUE_OFFSET = 1
// SELF_OFFSET is self value of the bar
const SELF_OFFSET = 2
// NAME_OFFSET is index into the names array
const NAME_OFFSET = 3
// ITEM_OFFSET Next bar. Each bar of the profile is represented by 4 number in a flat array.
const ITEM_OFFSET = 4
type ProfileTree struct {
Start int64
Level int
Value int64
Self int64
Level int
Name string
Function *Function
Inlined []*Function
locationID uint64
Nodes []*ProfileTree
Parent *ProfileTree
}
// levelsToTree converts flamebearer format into a tree. This is needed to then convert it into nested set format
// dataframe. This should be temporary, and ideally we should get some sort of tree struct directly from Phlare API.
func levelsToTree(levels []*querierv1.Level, names []string) *ProfileTree {
tree := &ProfileTree{
Start: 0,
Value: levels[0].Values[VALUE_OFFSET],
Self: levels[0].Values[SELF_OFFSET],
Level: 0,
Name: names[levels[0].Values[0]],
type Function struct {
FunctionName string
FileName string // optional
Line int64 // optional
}
parentsStack := []*ProfileTree{tree}
currentLevel := 1
// Cycle through each level
for {
if currentLevel >= len(levels) {
break
func (f Function) String() string {
return fmt.Sprintf("%s:%s:%d", f.FileName, f.FunctionName, f.Line)
}
// If we still have levels to go, this should not happen. Something is probably wrong with the flamebearer data.
if len(parentsStack) == 0 {
logger.Error("parentsStack is empty but we are not at the the last level", "currentLevel", currentLevel)
break
func (pt ProfileTree) String() string {
type branch struct {
nodes []*ProfileTree
treeprint.Tree
}
var nextParentsStack []*ProfileTree
currentParent := parentsStack[:1][0]
parentsStack = parentsStack[1:]
itemIndex := 0
// cumulative offset as items in flamebearer format have just relative to prev item
offset := int64(0)
// Cycle through bar in a level
for {
if itemIndex >= len(levels[currentLevel].Values) {
break
}
itemStart := levels[currentLevel].Values[itemIndex+START_OFFSET] + offset
itemValue := levels[currentLevel].Values[itemIndex+VALUE_OFFSET]
selfValue := levels[currentLevel].Values[itemIndex+SELF_OFFSET]
itemEnd := itemStart + itemValue
parentEnd := currentParent.Start + currentParent.Value
if itemStart >= currentParent.Start && itemEnd <= parentEnd {
// We have an item that is in the bounds of current parent item, so it should be its child
treeItem := &ProfileTree{
Start: itemStart,
Value: itemValue,
Self: selfValue,
Level: currentLevel,
Name: names[levels[currentLevel].Values[itemIndex+NAME_OFFSET]],
}
// Add to parent
currentParent.Nodes = append(currentParent.Nodes, treeItem)
// Add this item as parent for the next level
nextParentsStack = append(nextParentsStack, treeItem)
itemIndex += ITEM_OFFSET
// Update offset for next item. This is changing relative offset to absolute one.
offset = itemEnd
tree := treeprint.New()
for _, n := range []ProfileTree{pt} {
b := tree.AddBranch(fmt.Sprintf("%s: level %d self %d total %d", n.Function, n.Level, n.Self, n.Value))
remaining := append([]*branch{}, &branch{nodes: n.Nodes, Tree: b})
for len(remaining) > 0 {
current := remaining[0]
remaining = remaining[1:]
for _, n := range current.nodes {
if len(n.Nodes) > 0 {
remaining = append(remaining,
&branch{
nodes: n.Nodes, Tree: current.Tree.AddBranch(fmt.Sprintf("%s: level %d self %d total %d", n.Function, n.Level, n.Self, n.Value)),
},
)
} else {
// We went out of parents bounds so lets move to next parent. We will evaluate the same item again, but
// we will check if it is a child of the next parent item in line.
if len(parentsStack) == 0 {
logger.Error("parentsStack is empty but there are still items in current level", "currentLevel", currentLevel, "itemIndex", itemIndex)
current.Tree.AddNode(fmt.Sprintf("%s: level %d self %d total %d", n.Function, n.Level, n.Self, n.Value))
}
}
}
}
return tree.String()
}
// merge merges the node into the tree.
// it assumes src has only one leaf.
func (pt *ProfileTree) merge(src *ProfileTree) {
// find the node path where n should be inserted.
var parent, found *ProfileTree
// visit depth first the dst tree following the src tree
remaining := []*ProfileTree{pt}
for len(remaining) > 0 {
n := remaining[0]
remaining = remaining[1:]
if src.locationID == n.locationID {
if len(src.Nodes) == 0 {
// we have found the leaf
found = n
break
}
currentParent = parentsStack[:1][0]
parentsStack = parentsStack[1:]
// move src and last parent visited
parent = n
src = src.Nodes[0]
remaining = n.Nodes
continue
}
}
parentsStack = nextParentsStack
currentLevel++
if found == nil {
if parent == nil {
// Nothing in common can't be merged.
return
}
src.Parent = parent
parent.Nodes = append(parent.Nodes, src)
for p := parent; p != nil; p = p.Parent {
p.Value = p.Value + src.Value
}
return
}
found.Value = found.Value + src.Self
for p := found.Parent; p != nil; p = p.Parent {
p.Value = p.Value + src.Self
}
found.Self = found.Self + src.Self
}
return tree
func treeFromSample(profile *googlev1.Profile, sample *googlev1.Sample) *ProfileTree {
if len(sample.LocationId) == 0 {
return &ProfileTree{
Level: 0,
Value: sample.Value[0],
Function: &Function{
FunctionName: "root",
},
}
}
// The leaf is at locations[0].
locations := sample.LocationId
current := &ProfileTree{
Self: sample.Value[0],
Level: 0,
}
for len(locations) > 0 {
current.locationID = locations[0]
current.Value = sample.Value[0]
current.Level = len(locations)
// Ids in pprof format are 1 based. So to get the index in array from the id we need to subtract one.
lines := profile.Location[locations[0]-1].Line
if len(lines) == 0 {
locations = locations[1:]
continue
}
// The leaf is at lines[len(lines)-1].
current.Function = &Function{
FunctionName: profile.StringTable[profile.Function[lines[len(lines)-1].FunctionId-1].Name],
FileName: profile.StringTable[profile.Function[lines[len(lines)-1].FunctionId-1].Filename],
Line: lines[len(lines)-1].Line,
}
lines = lines[:len(lines)-1]
// If there are more than one line, each line inlined into the next line.
for len(lines) > 0 {
current.Inlined = append(current.Inlined, &Function{
FunctionName: profile.StringTable[profile.Function[lines[0].FunctionId-1].Name],
FileName: profile.StringTable[profile.Function[lines[0].FunctionId-1].Filename],
Line: lines[0].Line,
})
lines = lines[1:]
}
parent := &ProfileTree{
Nodes: []*ProfileTree{current},
}
current.Parent = parent
current = parent
locations = locations[1:]
}
if current.Function == nil {
current.Function = &Function{
FunctionName: "root",
}
current.Value = sample.Value[0]
current.locationID = 0
current.Self = 0
current.Level = 0
}
return current
}
func profileAsTree(profile *googlev1.Profile) *ProfileTree {
if profile == nil {
return nil
}
if len(profile.Sample) == 0 {
return nil
}
n := treeFromSample(profile, profile.Sample[0])
for _, sample := range profile.Sample[1:] {
n.merge(treeFromSample(profile, sample))
}
return n
}
type CustomMeta struct {
@@ -252,13 +321,19 @@ func treeToNestedSetDataFrame(tree *ProfileTree, profileTypeID string) *data.Fra
valueField.Config = &data.FieldConfig{Unit: normalizeUnit(parts[2])}
selfField.Config = &data.FieldConfig{Unit: normalizeUnit(parts[2])}
labelField := data.NewField("label", nil, []string{})
frame.Fields = data.Fields{levelField, valueField, selfField, labelField}
lineNumberField := data.NewField("line", nil, []int64{})
fileNameField := data.NewField("fileName", nil, []string{})
frame.Fields = data.Fields{levelField, valueField, selfField, labelField, lineNumberField, fileNameField}
walkTree(tree, func(tree *ProfileTree) {
levelField.Append(int64(tree.Level))
valueField.Append(tree.Value)
selfField.Append(tree.Self)
labelField.Append(tree.Name)
// todo: inline functions
// tree.Inlined
labelField.Append(tree.Function.FunctionName)
lineNumberField.Append(tree.Function.Line)
fileNameField.Append(tree.Function.FileName)
})
return frame
}

View File

@@ -10,6 +10,7 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/data"
"github.com/stretchr/testify/require"
googlev1 "github.com/grafana/phlare/api/gen/proto/go/google/v1"
querierv1 "github.com/grafana/phlare/api/gen/proto/go/querier/v1"
typesv1 "github.com/grafana/phlare/api/gen/proto/go/types/v1"
)
@@ -105,85 +106,14 @@ func makeDataQuery() *backend.DataQuery {
}
}
// This is where the tests for the datasource backend live.
func Test_profileToDataFrame(t *testing.T) {
resp := &connect.Response[querierv1.SelectMergeStacktracesResponse]{
Msg: &querierv1.SelectMergeStacktracesResponse{
Flamegraph: &querierv1.FlameGraph{
Names: []string{"func1", "func2", "func3"},
Levels: []*querierv1.Level{
{Values: []int64{0, 20, 1, 2}},
{Values: []int64{0, 10, 3, 1, 4, 5, 5, 2}},
},
Total: 987,
MaxSelf: 123,
},
},
}
frame := responseToDataFrames(resp, "memory:alloc_objects:count:space:bytes")
require.Equal(t, 4, len(frame.Fields))
require.Equal(t, data.NewField("level", nil, []int64{0, 1, 1}), frame.Fields[0])
require.Equal(t, data.NewField("value", nil, []int64{20, 10, 5}).SetConfig(&data.FieldConfig{Unit: "short"}), frame.Fields[1])
require.Equal(t, data.NewField("self", nil, []int64{1, 3, 5}).SetConfig(&data.FieldConfig{Unit: "short"}), frame.Fields[2])
require.Equal(t, data.NewField("label", nil, []string{"func1", "func2", "func3"}), frame.Fields[3])
}
// This is where the tests for the datasource backend live.
func Test_levelsToTree(t *testing.T) {
t.Run("simple", func(t *testing.T) {
levels := []*querierv1.Level{
{Values: []int64{0, 100, 0, 0}},
{Values: []int64{0, 40, 0, 1, 0, 30, 0, 2}},
{Values: []int64{0, 15, 0, 3}},
}
tree := levelsToTree(levels, []string{"root", "func1", "func2", "func1:func3"})
require.Equal(t, &ProfileTree{
Start: 0, Value: 100, Level: 0, Name: "root", Nodes: []*ProfileTree{
{
Start: 0, Value: 40, Level: 1, Name: "func1", Nodes: []*ProfileTree{
{Start: 0, Value: 15, Level: 2, Name: "func1:func3"},
},
},
{Start: 40, Value: 30, Level: 1, Name: "func2"},
},
}, tree)
})
t.Run("medium", func(t *testing.T) {
levels := []*querierv1.Level{
{Values: []int64{0, 100, 0, 0}},
{Values: []int64{0, 40, 0, 1, 0, 30, 0, 2, 0, 30, 0, 3}},
{Values: []int64{0, 20, 0, 4, 50, 10, 0, 5}},
}
tree := levelsToTree(levels, []string{"root", "func1", "func2", "func3", "func1:func4", "func3:func5"})
require.Equal(t, &ProfileTree{
Start: 0, Value: 100, Level: 0, Name: "root", Nodes: []*ProfileTree{
{
Start: 0, Value: 40, Level: 1, Name: "func1", Nodes: []*ProfileTree{
{Start: 0, Value: 20, Level: 2, Name: "func1:func4"},
},
},
{Start: 40, Value: 30, Level: 1, Name: "func2"},
{
Start: 70, Value: 30, Level: 1, Name: "func3", Nodes: []*ProfileTree{
{Start: 70, Value: 10, Level: 2, Name: "func3:func5"},
},
},
},
}, tree)
})
}
func Test_treeToNestedDataFrame(t *testing.T) {
tree := &ProfileTree{
Start: 0, Value: 100, Level: 0, Self: 1, Name: "root", Nodes: []*ProfileTree{
Value: 100, Level: 0, Self: 1, Function: &Function{FunctionName: "root"}, Nodes: []*ProfileTree{
{
Start: 10, Value: 40, Level: 1, Self: 2, Name: "func1",
Value: 40, Level: 1, Self: 2, Function: &Function{FunctionName: "func1", FileName: "1", Line: 1},
},
{Start: 60, Value: 30, Level: 1, Self: 3, Name: "func2", Nodes: []*ProfileTree{
{Start: 61, Value: 15, Level: 2, Self: 4, Name: "func1:func3"},
{Value: 30, Level: 1, Self: 3, Function: &Function{FunctionName: "func2", FileName: "2", Line: 2}, Nodes: []*ProfileTree{
{Value: 15, Level: 2, Self: 4, Function: &Function{FunctionName: "func1:func3", FileName: "3", Line: 3}},
}},
},
}
@@ -195,9 +125,309 @@ func Test_treeToNestedDataFrame(t *testing.T) {
data.NewField("value", nil, []int64{100, 40, 30, 15}).SetConfig(&data.FieldConfig{Unit: "short"}),
data.NewField("self", nil, []int64{1, 2, 3, 4}).SetConfig(&data.FieldConfig{Unit: "short"}),
data.NewField("label", nil, []string{"root", "func1", "func2", "func1:func3"}),
data.NewField("line", nil, []int64{0, 1, 2, 3}),
data.NewField("fileName", nil, []string{"", "1", "2", "3"}),
}, frame.Fields)
}
var fooProfile = &googlev1.Profile{
Location: []*googlev1.Location{
{Id: 1, Line: []*googlev1.Line{{Line: 5, FunctionId: 4}, {Line: 1, FunctionId: 1}}},
{Id: 2, Line: []*googlev1.Line{{Line: 2, FunctionId: 2}}},
{Id: 3, Line: []*googlev1.Line{{Line: 3, FunctionId: 3}}},
},
Function: []*googlev1.Function{
{Id: 1, Name: 1, Filename: 4},
{Id: 2, Name: 2, Filename: 4},
{Id: 3, Name: 3, Filename: 5},
{Id: 4, Name: 6, Filename: 5},
},
StringTable: []string{"", "foo", "bar", "baz", "file1", "file2", "inline"},
}
func Test_treeFromSample(t *testing.T) {
for _, tc := range []struct {
name string
s *googlev1.Sample
p *googlev1.Profile
want *ProfileTree
}{
{
name: "empty lines",
s: &googlev1.Sample{LocationId: []uint64{1, 2, 3}, Value: []int64{10}},
p: &googlev1.Profile{
Location: []*googlev1.Location{
{Id: 1, Line: []*googlev1.Line{}},
{Id: 2, Line: []*googlev1.Line{}},
{Id: 3, Line: []*googlev1.Line{}},
},
Function: []*googlev1.Function{},
},
want: &ProfileTree{
Value: 10,
Function: &Function{
FunctionName: "root",
},
},
},
{
name: "empty locations",
s: &googlev1.Sample{LocationId: []uint64{}, Value: []int64{10}},
want: &ProfileTree{
Value: 10,
Function: &Function{
FunctionName: "root",
},
},
},
{
name: "multiple locations and inlines",
s: &googlev1.Sample{LocationId: []uint64{3, 2, 1}, Value: []int64{10}},
p: fooProfile,
want: &ProfileTree{
Value: 10,
Function: &Function{
FunctionName: "root",
},
Nodes: []*ProfileTree{
{
Value: 10,
locationID: 1,
Level: 1,
Function: &Function{
FunctionName: "foo",
FileName: "file1",
Line: 1,
},
Inlined: []*Function{
{
FunctionName: "inline",
FileName: "file2",
Line: 5,
},
},
Nodes: []*ProfileTree{
{
Value: 10,
locationID: 2,
Level: 2,
Function: &Function{
FunctionName: "bar",
FileName: "file1",
Line: 2,
},
Nodes: []*ProfileTree{
{
Value: 10,
Self: 10,
locationID: 3,
Level: 3,
Function: &Function{
FunctionName: "baz",
FileName: "file2",
Line: 3,
},
},
},
},
},
},
},
},
},
} {
t.Run(tc.name, func(t *testing.T) {
setParents(tc.want)
actual := treeFromSample(tc.p, tc.s)
require.Equal(t, tc.want, actual, "want\n%s\n got\n%s", tc.want, actual)
})
}
}
func Test_TreeString(t *testing.T) {
t.Log(treeFromSample(fooProfile, &googlev1.Sample{LocationId: []uint64{3, 2, 1}, Value: []int64{10}}))
}
func Test_profileAsTree(t *testing.T) {
for _, tc := range []struct {
name string
want *ProfileTree
in *googlev1.Profile
}{
{name: "empty"},
{name: "no sample", in: &googlev1.Profile{}},
{
name: "same locations",
in: &googlev1.Profile{
Sample: []*googlev1.Sample{
{LocationId: []uint64{3, 2, 1}, Value: []int64{10}},
{LocationId: []uint64{3, 2, 1}, Value: []int64{30}},
},
Location: fooProfile.Location,
Function: fooProfile.Function,
StringTable: fooProfile.StringTable,
},
want: &ProfileTree{
Value: 40,
Function: &Function{
FunctionName: "root",
},
Nodes: []*ProfileTree{
{
Value: 40,
locationID: 1,
Level: 1,
Function: &Function{
FunctionName: "foo",
FileName: "file1",
Line: 1,
},
Inlined: []*Function{
{
FunctionName: "inline",
FileName: "file2",
Line: 5,
},
},
Nodes: []*ProfileTree{
{
Value: 40,
locationID: 2,
Level: 2,
Function: &Function{
FunctionName: "bar",
FileName: "file1",
Line: 2,
},
Nodes: []*ProfileTree{
{
Value: 40,
Self: 40,
locationID: 3,
Level: 3,
Function: &Function{
FunctionName: "baz",
FileName: "file2",
Line: 3,
},
},
},
},
},
},
},
},
},
{
name: "different locations",
in: &googlev1.Profile{
Sample: []*googlev1.Sample{
{LocationId: []uint64{3, 2, 1}, Value: []int64{15}}, // foo -> bar -> baz
{LocationId: []uint64{3, 2, 1}, Value: []int64{30}}, // foo -> bar -> baz
{LocationId: []uint64{3, 2}, Value: []int64{20}}, // bar -> baz
{LocationId: []uint64{2, 1}, Value: []int64{40}}, // foo -> bar
{LocationId: []uint64{1}, Value: []int64{5}}, // foo
{LocationId: []uint64{}, Value: []int64{5}},
},
Location: fooProfile.Location,
Function: fooProfile.Function,
StringTable: fooProfile.StringTable,
},
want: &ProfileTree{
Value: 110,
Function: &Function{
FunctionName: "root",
},
Nodes: []*ProfileTree{
{
Value: 90,
Self: 5,
locationID: 1,
Level: 1,
Function: &Function{
FunctionName: "foo",
FileName: "file1",
Line: 1,
},
Inlined: []*Function{
{
FunctionName: "inline",
FileName: "file2",
Line: 5,
},
},
Nodes: []*ProfileTree{
{
Value: 85,
Self: 40,
locationID: 2,
Level: 2,
Function: &Function{
FunctionName: "bar",
FileName: "file1",
Line: 2,
},
Nodes: []*ProfileTree{
{
Value: 45,
Self: 45,
locationID: 3,
Level: 3,
Function: &Function{
FunctionName: "baz",
FileName: "file2",
Line: 3,
},
},
},
},
},
},
{
locationID: 2,
Value: 20,
Self: 0,
Level: 1,
Function: &Function{
FunctionName: "bar",
FileName: "file1",
Line: 2,
},
Nodes: []*ProfileTree{
{
locationID: 3,
Value: 20,
Self: 20,
Level: 2,
Function: &Function{
FunctionName: "baz",
FileName: "file2",
Line: 3,
},
},
},
},
},
},
},
} {
t.Run(tc.name, func(t *testing.T) {
if tc.want != nil {
setParents(tc.want)
}
actual := profileAsTree(tc.in)
require.Equal(t, tc.want, actual, "want\n%s\n got\n%s", tc.want, actual)
})
}
}
func setParents(root *ProfileTree) {
for _, n := range root.Nodes {
n.Parent = root
setParents(n)
}
}
func Test_seriesToDataFrame(t *testing.T) {
t.Run("single series", func(t *testing.T) {
resp := &connect.Response[querierv1.SelectSeriesResponse]{
@@ -312,3 +542,31 @@ func (f *FakeClient) SelectSeries(ctx context.Context, req *connect.Request[quer
},
}, nil
}
func (f *FakeClient) SelectMergeProfile(ctx context.Context, c *connect.Request[querierv1.SelectMergeProfileRequest]) (*connect.Response[googlev1.Profile], error) {
f.Req = c
p := &googlev1.Profile{
SampleType: []*googlev1.ValueType{
{Type: 1, Unit: 2},
},
Sample: []*googlev1.Sample{
{
Value: []int64{1},
LocationId: []uint64{
1, 2,
},
},
},
Mapping: []*googlev1.Mapping{{Id: 1}},
Location: []*googlev1.Location{
{Id: 1, MappingId: 1, Line: []*googlev1.Line{{FunctionId: 1}}},
{Id: 2, MappingId: 1, Line: []*googlev1.Line{{FunctionId: 2}}},
},
Function: []*googlev1.Function{
{Id: 1, Name: 3},
{Id: 2, Name: 4},
},
StringTable: []string{"", "cpu", "nanoseconds", "foo", "bar"},
}
return connect.NewResponse(p), nil
}

View File

@@ -45,7 +45,7 @@ const FlameGraphTopTableContainer = ({
let label, self, value;
let table: { [key: string]: TableData } = {};
if (data.fields.length === 4) {
if (data.fields.length === 6) {
const valueValues = data.fields[1].values;
const selfValues = data.fields[2].values;
const labelValues = data.fields[3].values;