github.com/grafana/pyroscope@v1.18.0/pkg/operations/v2/model.go (about)

     1  package v2
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"net/http"
     7  	"slices"
     8  	"strings"
     9  	"time"
    10  
    11  	"github.com/gorilla/mux"
    12  	"github.com/pkg/errors"
    13  
    14  	metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1"
    15  	"github.com/grafana/pyroscope/pkg/operations"
    16  )
    17  
    18  type blockQuery struct {
    19  	From string
    20  	To   string
    21  	View string
    22  
    23  	parsedFrom time.Time
    24  	parsedTo   time.Time
    25  }
    26  
    27  func readQuery(r *http.Request) *blockQuery {
    28  	queryFrom := r.URL.Query().Get("queryFrom")
    29  	if queryFrom == "" {
    30  		queryFrom = "now-24h"
    31  	}
    32  	parsedFrom, _ := operations.ParseTime(queryFrom)
    33  	queryTo := r.URL.Query().Get("queryTo")
    34  	if queryTo == "" {
    35  		queryTo = "now"
    36  	}
    37  	parsedTo, _ := operations.ParseTime(queryTo)
    38  	view := r.URL.Query().Get("view")
    39  	if view == "" {
    40  		view = "table"
    41  	}
    42  	return &blockQuery{
    43  		From:       queryFrom,
    44  		To:         queryTo,
    45  		View:       view,
    46  		parsedFrom: parsedFrom,
    47  		parsedTo:   parsedTo,
    48  	}
    49  }
    50  
    51  type blockDetails struct {
    52  	ID                string
    53  	MinTime           string
    54  	MaxTime           string
    55  	Duration          int
    56  	FormattedDuration string
    57  	Shard             uint32
    58  	CompactionLevel   uint32
    59  	Size              string
    60  	Datasets          []datasetDetails
    61  	BlockTenant       string // Empty for multi-tenant blocks (compaction level 0)
    62  }
    63  
    64  type labelPair struct {
    65  	Key   string
    66  	Value string
    67  }
    68  
    69  type labelSet struct {
    70  	Pairs []labelPair
    71  }
    72  
    73  type datasetDetails struct {
    74  	Tenant             string
    75  	Name               string
    76  	MinTime            string
    77  	MaxTime            string
    78  	Size               string
    79  	ProfilesSize       string
    80  	IndexSize          string
    81  	SymbolsSize        string
    82  	ProfilesPercentage float64
    83  	IndexPercentage    float64
    84  	SymbolsPercentage  float64
    85  	LabelSets          []labelSet
    86  }
    87  
    88  type blockGroup struct {
    89  	MinTime                 time.Time
    90  	FormattedMinTime        string
    91  	Blocks                  []*blockDetails
    92  	MinTimeAge              string
    93  	MaxBlockDurationMinutes int
    94  }
    95  
    96  type blockListResult struct {
    97  	BlockGroups          []*blockGroup
    98  	MaxBlocksPerGroup    int
    99  	GroupDurationMinutes int
   100  }
   101  
   102  // Sorts a slice of block groups by MinTime in descending order.
   103  func sortBlockGroupsByMinTimeDec(bg []*blockGroup) {
   104  	slices.SortFunc(bg, func(a, b *blockGroup) int {
   105  		return b.MinTime.Compare(a.MinTime)
   106  	})
   107  }
   108  
   109  // Sorts a slice of block details by MinTime in descending order.
   110  func sortBlockDetailsByMinTimeDec(bd []*blockDetails) {
   111  	slices.SortFunc(bd, func(a, b *blockDetails) int {
   112  		return strings.Compare(b.MinTime, a.MinTime)
   113  	})
   114  }
   115  
   116  type profileInfo struct {
   117  	RowNumber   int
   118  	Timestamp   string
   119  	SeriesIndex uint32
   120  	ProfileType string
   121  	SampleCount int
   122  }
   123  
   124  type treeNode struct {
   125  	Name           string
   126  	Value          uint64
   127  	Percent        float64
   128  	Location       string // File path and line number (e.g., "pkg/util/logger.go:L91")
   129  	FormattedValue string // Formatted value with unit (e.g., "1.5 MB", "250 ms")
   130  	Children       []*treeNode
   131  }
   132  
   133  type profileCallTreePageContent struct {
   134  	User        string
   135  	BlockID     string
   136  	Shard       uint32
   137  	BlockTenant string
   138  	Dataset     *datasetDetails
   139  	Timestamp   string
   140  	ProfileInfo *profileMetadata
   141  	Tree        *treeNode
   142  	Now         string
   143  }
   144  
   145  type profileMetadata struct {
   146  	Labels      []labelPair
   147  	SampleCount int
   148  	Unit        string
   149  	ProfileType string
   150  }
   151  
   152  type tsdbIndexInfo struct {
   153  	From           string
   154  	Through        string
   155  	Checksum       uint32
   156  	Series         []seriesInfo
   157  	Symbols        []string
   158  	LabelValueSets []labelValueSet
   159  }
   160  
   161  type labelValueSet struct {
   162  	LabelName   string
   163  	LabelValues []string
   164  }
   165  
   166  type seriesInfo struct {
   167  	SeriesIndex uint32
   168  	SeriesRef   uint64
   169  	Labels      []labelPair
   170  }
   171  
   172  type datasetIndexPageContent struct {
   173  	User        string
   174  	BlockID     string
   175  	Shard       uint32
   176  	BlockTenant string
   177  	Dataset     *datasetDetails
   178  	TSDBIndex   *tsdbIndexInfo
   179  	Now         string
   180  }
   181  
   182  type symbolsInfo struct {
   183  	Strings        []symbolEntry
   184  	TotalStrings   int
   185  	Functions      []functionEntry
   186  	TotalFunctions int
   187  	Locations      []locationEntry
   188  	TotalLocations int
   189  	Mappings       []mappingEntry
   190  	TotalMappings  int
   191  }
   192  
   193  type symbolEntry struct {
   194  	Index  int
   195  	Symbol string
   196  }
   197  
   198  type functionEntry struct {
   199  	Index      int
   200  	ID         uint64
   201  	Name       string
   202  	SystemName string
   203  	Filename   string
   204  	StartLine  uint32
   205  }
   206  
   207  type locationLine struct {
   208  	FunctionName string
   209  	Line         int64
   210  }
   211  
   212  type locationEntry struct {
   213  	Index     int
   214  	ID        uint64
   215  	Address   uint64
   216  	MappingID uint32
   217  	Lines     []locationLine
   218  }
   219  
   220  type mappingEntry struct {
   221  	Index       int
   222  	ID          uint64
   223  	MemoryStart uint64
   224  	MemoryLimit uint64
   225  	FileOffset  uint64
   226  	Filename    string
   227  	BuildID     string
   228  }
   229  
   230  type datasetSymbolsPageContent struct {
   231  	User        string
   232  	BlockID     string
   233  	Shard       uint32
   234  	BlockTenant string
   235  	Dataset     *datasetDetails
   236  	Symbols     *symbolsInfo
   237  	Page        int
   238  	PageSize    int
   239  	TotalPages  int
   240  	HasPrevPage bool
   241  	HasNextPage bool
   242  	Tab         string
   243  	Now         string
   244  }
   245  
   246  const emptyDatasetPlaceholder = "_empty"
   247  
   248  type datasetRequest struct {
   249  	TenantID    string
   250  	BlockID     string
   251  	BlockTenant string
   252  	DatasetName string
   253  	Shard       uint32
   254  }
   255  
   256  func parseDatasetRequest(r *http.Request) (*datasetRequest, error) {
   257  	vars := mux.Vars(r)
   258  
   259  	tenantID := vars["tenant"]
   260  	if tenantID == "" {
   261  		return nil, errors.New("No tenant id provided")
   262  	}
   263  
   264  	blockID := vars["block"]
   265  	if blockID == "" {
   266  		return nil, errors.New("No block id provided")
   267  	}
   268  
   269  	datasetName := r.URL.Query().Get("dataset")
   270  	if datasetName == "" {
   271  		return nil, errors.New("No dataset name provided")
   272  	}
   273  	if datasetName == emptyDatasetPlaceholder {
   274  		datasetName = ""
   275  	}
   276  
   277  	shardStr := r.URL.Query().Get("shard")
   278  	if shardStr == "" {
   279  		return nil, errors.New("No shard provided")
   280  	}
   281  	var shard uint32
   282  	if _, err := fmt.Sscanf(shardStr, "%d", &shard); err != nil {
   283  		return nil, errors.Wrap(err, "invalid shard parameter")
   284  	}
   285  
   286  	blockTenant := r.URL.Query().Get("block_tenant")
   287  
   288  	return &datasetRequest{
   289  		TenantID:    tenantID,
   290  		BlockID:     blockID,
   291  		BlockTenant: blockTenant,
   292  		DatasetName: datasetName,
   293  		Shard:       shard,
   294  	}, nil
   295  }
   296  
   297  func (h *Handlers) getDatasetMetadata(ctx context.Context, req *datasetRequest) (*metastorev1.BlockMeta, *metastorev1.Dataset, error) {
   298  	metadataResp, err := h.MetastoreClient.GetBlockMetadata(ctx, &metastorev1.GetBlockMetadataRequest{
   299  		Blocks: &metastorev1.BlockList{
   300  			Tenant: req.BlockTenant,
   301  			Shard:  req.Shard,
   302  			Blocks: []string{req.BlockID},
   303  		},
   304  	})
   305  	if err != nil {
   306  		return nil, nil, errors.Wrap(err, "failed to get block metadata")
   307  	}
   308  
   309  	if len(metadataResp.Blocks) == 0 {
   310  		return nil, nil, errors.New("Block not found")
   311  	}
   312  
   313  	blockMeta := metadataResp.Blocks[0]
   314  
   315  	var foundDataset *metastorev1.Dataset
   316  	for _, ds := range blockMeta.Datasets {
   317  		dsName := blockMeta.StringTable[ds.Name]
   318  		if dsName == req.DatasetName {
   319  			foundDataset = ds
   320  			break
   321  		}
   322  	}
   323  
   324  	if foundDataset == nil {
   325  		return nil, nil, errors.New("Dataset not found")
   326  	}
   327  
   328  	return blockMeta, foundDataset, nil
   329  }