VictoriaMetrics/app/vlselect/logsql/logsql.go

110 lines
2.5 KiB
Go
Raw Normal View History

package logsql
import (
"context"
2024-05-15 02:55:44 +00:00
"fmt"
"math"
"net/http"
2024-05-15 02:55:44 +00:00
"time"
"github.com/VictoriaMetrics/VictoriaMetrics/app/vlstorage"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/bytesutil"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/httpserver"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/httputils"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logstorage"
2024-05-15 02:55:44 +00:00
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
)
// ProcessQueryRequest handles /select/logsql/query request.
func ProcessQueryRequest(ctx context.Context, w http.ResponseWriter, r *http.Request) {
// Extract tenantID
tenantID, err := logstorage.GetTenantIDFromRequest(r)
if err != nil {
httpserver.Errorf(w, r, "%s", err)
return
}
2024-05-15 02:55:44 +00:00
// Parse query
qStr := r.FormValue("query")
q, err := logstorage.ParseQuery(qStr)
if err != nil {
httpserver.Errorf(w, r, "cannot parse query [%s]: %s", qStr, err)
return
}
2024-05-15 02:55:44 +00:00
// Parse optional start and end args
start, okStart, err := getTimeNsec(r, "start")
if err != nil {
httpserver.Errorf(w, r, "%s", err)
return
}
end, okEnd, err := getTimeNsec(r, "end")
if err != nil {
httpserver.Errorf(w, r, "%s", err)
return
}
if okStart || okEnd {
if !okStart {
start = math.MinInt64
}
if !okEnd {
end = math.MaxInt64
}
q.AddTimeFilter(start, end)
}
// Parse limit query arg
limit, err := httputils.GetInt(r, "limit")
if err != nil {
httpserver.Errorf(w, r, "%s", err)
return
}
2024-05-14 01:05:03 +00:00
if limit > 0 {
q.AddPipeLimit(uint64(limit))
}
2024-05-15 02:55:44 +00:00
q.Optimize()
2024-05-14 01:05:03 +00:00
tenantIDs := []logstorage.TenantID{tenantID}
2024-05-14 01:05:03 +00:00
bw := getBufferedWriter(w)
writeBlock := func(_ uint, timestamps []int64, columns []logstorage.BlockColumn) {
if len(columns) == 0 {
return
}
bb := blockResultPool.Get()
for i := range timestamps {
WriteJSONRow(bb, columns, i)
}
2024-05-14 01:05:03 +00:00
bw.WriteIgnoreErrors(bb.B)
blockResultPool.Put(bb)
}
2024-05-15 02:55:44 +00:00
w.Header().Set("Content-Type", "application/stream+json; charset=utf-8")
2024-05-14 01:05:03 +00:00
err = vlstorage.RunQuery(ctx, tenantIDs, q, writeBlock)
2024-05-14 01:05:03 +00:00
bw.FlushIgnoreErrors()
putBufferedWriter(bw)
if err != nil {
httpserver.Errorf(w, r, "cannot execute query [%s]: %s", qStr, err)
}
}
var blockResultPool bytesutil.ByteBufferPool
2024-05-15 02:55:44 +00:00
func getTimeNsec(r *http.Request, argName string) (int64, bool, error) {
s := r.FormValue(argName)
if s == "" {
return 0, false, nil
}
currentTimestamp := float64(time.Now().UnixNano()) / 1e9
secs, err := promutils.ParseTimeAt(s, currentTimestamp)
if err != nil {
return 0, false, fmt.Errorf("cannot parse %s=%s: %w", argName, s, err)
}
return int64(secs * 1e9), true, nil
}