(ctx context.Context, req *tempopb.SearchTagValuesRequest)
| 548 | } |
| 549 | |
| 550 | func (q *Querier) SearchTagValuesV2(ctx context.Context, req *tempopb.SearchTagValuesRequest) (*tempopb.SearchTagValuesV2Response, error) { |
| 551 | userID, err := validation.ExtractValidTenantID(ctx) |
| 552 | if err != nil { |
| 553 | return nil, fmt.Errorf("error extracting org id in Querier.SearchTagValues: %w", err) |
| 554 | } |
| 555 | |
| 556 | maxDataSize := q.limits.MaxBytesPerTagValuesQuery(userID) |
| 557 | distinctValues := collector.NewDistinctValue(maxDataSize, req.MaxTagValues, req.StaleValueThreshold, func(v tempopb.TagValue) int { return len(v.Type) + len(v.Value) }) |
| 558 | var inspectedBytes uint64 |
| 559 | |
| 560 | // Virtual tags values. Get these first. |
| 561 | virtualVals := search.GetVirtualTagValuesV2(req.TagName) |
| 562 | for _, v := range virtualVals { |
| 563 | // no need to stop early here, virtual tags are small |
| 564 | distinctValues.Collect(v) |
| 565 | } |
| 566 | |
| 567 | // with v2 search we can confidently bail if GetVirtualTagValuesV2 gives us any hits. this doesn't work |
| 568 | // in v1 search b/c intrinsic tags like "status" are conflated with attributes named "status" |
| 569 | if virtualVals != nil { |
| 570 | // no data was read to collect virtual tags so 0 bytesRead |
| 571 | return valuesToV2Response(distinctValues, 0), nil |
| 572 | } |
| 573 | |
| 574 | results, err := q.forLiveStoreRing(ctx, func(ctx context.Context, client tempopb.QuerierClient) (any, error) { |
| 575 | return client.SearchTagValuesV2(ctx, req) |
| 576 | }) |
| 577 | if err != nil { |
| 578 | return nil, fmt.Errorf("error querying live-stores in Querier.SearchTagValues: %w", err) |
| 579 | } |
| 580 | |
| 581 | outer: |
| 582 | for _, result := range results { |
| 583 | resp := result.(*tempopb.SearchTagValuesV2Response) |
| 584 | if resp.Metrics != nil { |
| 585 | inspectedBytes += resp.Metrics.InspectedBytes |
| 586 | } |
| 587 | |
| 588 | for _, res := range resp.TagValues { |
| 589 | distinctValues.Collect(*res) |
| 590 | if distinctValues.Exceeded() { |
| 591 | break outer |
| 592 | } |
| 593 | } |
| 594 | } |
| 595 | |
| 596 | if distinctValues.Exceeded() { |
| 597 | _ = level.Warn(log.Logger).Log("msg", "Search of tag values exceeded limit, reduce cardinality or size of tags", "tag", req.TagName, "orgID", userID, "stopReason", distinctValues.StopReason()) |
| 598 | } |
| 599 | |
| 600 | return valuesToV2Response(distinctValues, inspectedBytes), nil |
| 601 | } |
| 602 | |
| 603 | func valuesToV2Response(distinctValues *collector.DistinctValue[tempopb.TagValue], bytesRead uint64) *tempopb.SearchTagValuesV2Response { |
| 604 | resp := &tempopb.SearchTagValuesV2Response{ |
no test coverage detected