mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
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:
20
go.mod
20
go.mod
@@ -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
36
go.sum
@@ -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=
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user