github.com/grafana/pyroscope@v1.18.0/pkg/frontend/readpath/queryfrontend/query_select_merge_span_profile.go (about)

     1  package queryfrontend
     2  
     3  import (
     4  	"context"
     5  
     6  	"connectrpc.com/connect"
     7  	"github.com/grafana/dskit/tenant"
     8  
     9  	querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1"
    10  	queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1"
    11  	phlaremodel "github.com/grafana/pyroscope/pkg/model"
    12  	"github.com/grafana/pyroscope/pkg/validation"
    13  )
    14  
    15  // TODO(kolesnikovae): Implement span selector.
    16  
    17  func (q *QueryFrontend) SelectMergeSpanProfile(
    18  	ctx context.Context,
    19  	c *connect.Request[querierv1.SelectMergeSpanProfileRequest],
    20  ) (*connect.Response[querierv1.SelectMergeSpanProfileResponse], error) {
    21  	tenantIDs, err := tenant.TenantIDs(ctx)
    22  	if err != nil {
    23  		return nil, connect.NewError(connect.CodeInvalidArgument, err)
    24  	}
    25  	empty, err := validation.SanitizeTimeRange(q.limits, tenantIDs, &c.Msg.Start, &c.Msg.End)
    26  	if err != nil {
    27  		return nil, connect.NewError(connect.CodeInvalidArgument, err)
    28  	}
    29  	if empty {
    30  		return connect.NewResponse(&querierv1.SelectMergeSpanProfileResponse{}), nil
    31  	}
    32  
    33  	_, err = phlaremodel.ParseProfileTypeSelector(c.Msg.ProfileTypeID)
    34  	if err != nil {
    35  		return nil, connect.NewError(connect.CodeInvalidArgument, err)
    36  	}
    37  
    38  	maxNodes, err := validation.ValidateMaxNodes(q.limits, tenantIDs, c.Msg.GetMaxNodes())
    39  	if err != nil {
    40  		return nil, connect.NewError(connect.CodeInvalidArgument, err)
    41  	}
    42  	labelSelector, err := buildLabelSelectorWithProfileType(c.Msg.LabelSelector, c.Msg.ProfileTypeID)
    43  	if err != nil {
    44  		return nil, connect.NewError(connect.CodeInvalidArgument, err)
    45  	}
    46  	report, err := q.querySingle(ctx, &queryv1.QueryRequest{
    47  		StartTime:     c.Msg.Start,
    48  		EndTime:       c.Msg.End,
    49  		LabelSelector: labelSelector,
    50  		Query: []*queryv1.Query{{
    51  			QueryType: queryv1.QueryType_QUERY_TREE,
    52  			Tree: &queryv1.TreeQuery{
    53  				MaxNodes:     maxNodes,
    54  				SpanSelector: c.Msg.SpanSelector,
    55  			},
    56  		}},
    57  	})
    58  	if err != nil {
    59  		return nil, err
    60  	}
    61  	if report == nil {
    62  		return connect.NewResponse(&querierv1.SelectMergeSpanProfileResponse{}), nil
    63  	}
    64  
    65  	var resp querierv1.SelectMergeSpanProfileResponse
    66  	switch c.Msg.Format {
    67  	case querierv1.ProfileFormat_PROFILE_FORMAT_TREE:
    68  		resp.Tree = report.Tree.Tree
    69  	default:
    70  		t, err := phlaremodel.UnmarshalTree(report.Tree.Tree)
    71  		if err != nil {
    72  			return nil, err
    73  		}
    74  		resp.Flamegraph = phlaremodel.NewFlameGraph(t, c.Msg.GetMaxNodes())
    75  	}
    76  	return connect.NewResponse(&resp), nil
    77  }