Pyroscope: Exemplar support for series queries (#113926)

* feat(pyroscope): Exemplar support for series queries

use enum flag, add exemplar flag to explore

disable exemplars on explore as well

tests

feature toggle

fixing tests

* resolve conflicts

* lint
This commit is contained in:
Alberto
2026-01-07 13:25:42 +01:00
committed by GitHub
parent 0b9046be15
commit 6fee200327
25 changed files with 306 additions and 32 deletions
@@ -8,14 +8,16 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/backend/tracing"
typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1"
"connectrpc.com/connect"
querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1"
"github.com/grafana/pyroscope/api/gen/proto/go/querier/v1/querierv1connect"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/trace"
querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1"
"github.com/grafana/pyroscope/api/gen/proto/go/querier/v1/querierv1connect"
)
type ProfileType struct {
@@ -49,6 +51,13 @@ type Point struct {
// Milliseconds unix timestamp
Timestamp int64
Annotations []*typesv1.ProfileAnnotation
Exemplars []*Exemplar
}
type Exemplar struct {
Id string
Value uint64
Timestamp int64
}
type ProfileResponse struct {
@@ -99,7 +108,7 @@ func (c *PyroscopeClient) ProfileTypes(ctx context.Context, start int64, end int
}
}
func (c *PyroscopeClient) GetSeries(ctx context.Context, profileTypeID string, labelSelector string, start int64, end int64, groupBy []string, limit *int64, step float64) (*SeriesResponse, error) {
func (c *PyroscopeClient) GetSeries(ctx context.Context, profileTypeID string, labelSelector string, start int64, end int64, groupBy []string, limit *int64, step float64, exemplarType typesv1.ExemplarType) (*SeriesResponse, error) {
ctx, span := tracing.DefaultTracer().Start(ctx, "datasource.pyroscope.GetSeries", trace.WithAttributes(attribute.String("profileTypeID", profileTypeID), attribute.String("labelSelector", labelSelector)))
defer span.End()
req := connect.NewRequest(&querierv1.SelectSeriesRequest{
@@ -110,6 +119,7 @@ func (c *PyroscopeClient) GetSeries(ctx context.Context, profileTypeID string, l
Step: step,
GroupBy: groupBy,
Limit: limit,
ExemplarType: exemplarType,
})
resp, err := c.connectClient.SelectSeries(ctx, req)
@@ -137,6 +147,16 @@ func (c *PyroscopeClient) GetSeries(ctx context.Context, profileTypeID string, l
Timestamp: p.Timestamp,
Annotations: p.Annotations,
}
if len(p.Exemplars) > 0 {
points[i].Exemplars = make([]*Exemplar, len(p.Exemplars))
for j, e := range p.Exemplars {
points[i].Exemplars[j] = &Exemplar{
Id: e.ProfileId,
Value: e.Value,
Timestamp: e.Timestamp,
}
}
}
}
series[i] = &Series{