ProcessStatsQueryRangeRequest handles /select/logsql/stats_query_range request. See https://docs.victoriametrics.com/victorialogs/querying/#querying-log-range-stats
(ctx context.Context, w http.ResponseWriter, r *http.Request)
| 692 | // |
| 693 | // See https://docs.victoriametrics.com/victorialogs/querying/#querying-log-range-stats |
| 694 | func ProcessStatsQueryRangeRequest(ctx context.Context, w http.ResponseWriter, r *http.Request) { |
| 695 | q, tenantIDs, err := parseCommonArgs(r) |
| 696 | if err != nil { |
| 697 | httpserver.SendPrometheusError(w, r, err) |
| 698 | return |
| 699 | } |
| 700 | |
| 701 | // Obtain step |
| 702 | stepStr := r.FormValue("step") |
| 703 | if stepStr == "" { |
| 704 | stepStr = "1d" |
| 705 | } |
| 706 | step, err := timeutil.ParseDuration(stepStr) |
| 707 | if err != nil { |
| 708 | err = fmt.Errorf("cannot parse 'step' arg: %s", err) |
| 709 | httpserver.SendPrometheusError(w, r, err) |
| 710 | return |
| 711 | } |
| 712 | if step <= 0 { |
| 713 | err := fmt.Errorf("'step' must be bigger than zero") |
| 714 | httpserver.SendPrometheusError(w, r, err) |
| 715 | return |
| 716 | } |
| 717 | |
| 718 | // Obtain `by(...)` fields from the last `| stats` pipe in q. |
| 719 | // Add `_time:step` to the `by(...)` list. |
| 720 | byFields, err := q.GetStatsByFieldsAddGroupingByTime(int64(step)) |
| 721 | if err != nil { |
| 722 | httpserver.SendPrometheusError(w, r, err) |
| 723 | return |
| 724 | } |
| 725 | |
| 726 | m := make(map[string]*statsSeries) |
| 727 | var mLock sync.Mutex |
| 728 | |
| 729 | writeBlock := func(_ uint, db *logstorage.DataBlock) { |
| 730 | rowsCount := db.RowsCount() |
| 731 | |
| 732 | columns := db.Columns |
| 733 | clonedColumnNames := make([]string, len(columns)) |
| 734 | for i, c := range columns { |
| 735 | clonedColumnNames[i] = strings.Clone(c.Name) |
| 736 | } |
| 737 | for i := 0; i < rowsCount; i++ { |
| 738 | // Do not move q.GetTimestamp() outside writeBlock, since ts |
| 739 | // must be initialized to query timestamp for every processed log row. |
| 740 | // See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8312 |
| 741 | ts := q.GetTimestamp() |
| 742 | labels := make([]logstorage.Field, 0, len(byFields)) |
| 743 | for j, c := range columns { |
| 744 | if c.Name == "_time" { |
| 745 | nsec, ok := logstorage.TryParseTimestampRFC3339Nano(c.Values[i]) |
| 746 | if ok { |
| 747 | ts = nsec |
| 748 | continue |
| 749 | } |
| 750 | } |
| 751 | if slices.Contains(byFields, c.Name) { |
no test coverage detected
searching dependent graphs…