mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-12 09:38:59 +08:00
parser updated for pagination
This commit is contained in:
parent
0807a0ae26
commit
eb28ece680
@ -3047,6 +3047,7 @@ func (r *ClickHouseReader) GetLogs(ctx context.Context, params *model.LogsFilter
|
|||||||
return nil, apiErr
|
return nil, apiErr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isPaginatePrev := logs.CheckIfPrevousPaginateAndModifyOrder(params)
|
||||||
filterSql, err := logs.GenerateSQLWhere(fields, params)
|
filterSql, err := logs.GenerateSQLWhere(fields, params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, &model.ApiError{Err: err, Typ: model.ErrorBadData}
|
return nil, &model.ApiError{Err: err, Typ: model.ErrorBadData}
|
||||||
@ -3064,7 +3065,12 @@ func (r *ClickHouseReader) GetLogs(ctx context.Context, params *model.LogsFilter
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, &model.ApiError{Err: err, Typ: model.ErrorInternal}
|
return nil, &model.ApiError{Err: err, Typ: model.ErrorInternal}
|
||||||
}
|
}
|
||||||
|
if isPaginatePrev {
|
||||||
|
// rever the results from db
|
||||||
|
for i, j := 0, len(response)-1; i < j; i, j = i+1, j-1 {
|
||||||
|
response[i], response[j] = response[j], response[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
return &response, nil
|
return &response, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3093,8 +3099,8 @@ func (r *ClickHouseReader) TailLogs(ctx context.Context, client *model.LogsTailC
|
|||||||
}
|
}
|
||||||
|
|
||||||
var idStart string
|
var idStart string
|
||||||
if client.Filter.IdStart != "" {
|
if client.Filter.IdGt != "" {
|
||||||
idStart = client.Filter.IdStart
|
idStart = client.Filter.IdGt
|
||||||
}
|
}
|
||||||
|
|
||||||
ticker := time.NewTicker(time.Duration(r.liveTailRefreshSeconds) * time.Second)
|
ticker := time.NewTicker(time.Duration(r.liveTailRefreshSeconds) * time.Second)
|
||||||
|
@ -1902,7 +1902,7 @@ func (aH *APIHandler) RegisterLogsRoutes(router *mux.Router) {
|
|||||||
subRouter.HandleFunc("", ViewAccess(aH.getLogs)).Methods(http.MethodGet)
|
subRouter.HandleFunc("", ViewAccess(aH.getLogs)).Methods(http.MethodGet)
|
||||||
subRouter.HandleFunc("/tail", ViewAccess(aH.tailLogs)).Methods(http.MethodGet)
|
subRouter.HandleFunc("/tail", ViewAccess(aH.tailLogs)).Methods(http.MethodGet)
|
||||||
subRouter.HandleFunc("/fields", ViewAccess(aH.logFields)).Methods(http.MethodGet)
|
subRouter.HandleFunc("/fields", ViewAccess(aH.logFields)).Methods(http.MethodGet)
|
||||||
subRouter.HandleFunc("/fields", ViewAccess(aH.logFieldUpdate)).Methods(http.MethodPost)
|
subRouter.HandleFunc("/fields", EditAccess(aH.logFieldUpdate)).Methods(http.MethodPost)
|
||||||
subRouter.HandleFunc("/aggregate", ViewAccess(aH.logAggregate)).Methods(http.MethodGet)
|
subRouter.HandleFunc("/aggregate", ViewAccess(aH.logAggregate)).Methods(http.MethodGet)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,8 +28,11 @@ const (
|
|||||||
ORDER_BY = "orderBy"
|
ORDER_BY = "orderBy"
|
||||||
TIMESTAMP_START = "timestampStart"
|
TIMESTAMP_START = "timestampStart"
|
||||||
TIMESTAMP_END = "timestampEnd"
|
TIMESTAMP_END = "timestampEnd"
|
||||||
IDSTART = "idStart"
|
IdGt = "idGt"
|
||||||
IDEND = "idEnd"
|
IdLT = "idLt"
|
||||||
|
TIMESTAMP = "timestamp"
|
||||||
|
ASC = "asc"
|
||||||
|
DESC = "desc"
|
||||||
)
|
)
|
||||||
|
|
||||||
var tokenRegex, _ = regexp.Compile(`(?i)(and( )*?|or( )*?)?(([\w.-]+ (in|nin) \([^(]+\))|([\w.]+ (gt|lt|gte|lte) (')?[\S]+(')?)|([\w.]+ (contains|ncontains)) '[^']+')`)
|
var tokenRegex, _ = regexp.Compile(`(?i)(and( )*?|or( )*?)?(([\w.-]+ (in|nin) \([^(]+\))|([\w.]+ (gt|lt|gte|lte) (')?[\S]+(')?)|([\w.]+ (contains|ncontains)) '[^']+')`)
|
||||||
@ -72,11 +75,11 @@ func ParseLogFilterParams(r *http.Request) (*model.LogsFilterParams, error) {
|
|||||||
}
|
}
|
||||||
res.TimestampEnd = uint64(ts)
|
res.TimestampEnd = uint64(ts)
|
||||||
}
|
}
|
||||||
if val, ok := params[IDSTART]; ok {
|
if val, ok := params[IdGt]; ok {
|
||||||
res.IdStart = val[0]
|
res.IdGt = val[0]
|
||||||
}
|
}
|
||||||
if val, ok := params[IDEND]; ok {
|
if val, ok := params[IdLT]; ok {
|
||||||
res.IdEnd = val[0]
|
res.IdLT = val[0]
|
||||||
}
|
}
|
||||||
return &res, nil
|
return &res, nil
|
||||||
}
|
}
|
||||||
@ -94,8 +97,8 @@ func ParseLiveTailFilterParams(r *http.Request) (*model.LogsFilterParams, error)
|
|||||||
}
|
}
|
||||||
res.TimestampStart = uint64(ts)
|
res.TimestampStart = uint64(ts)
|
||||||
}
|
}
|
||||||
if val, ok := params[IDSTART]; ok {
|
if val, ok := params[IdGt]; ok {
|
||||||
res.IdStart = val[0]
|
res.IdGt = val[0]
|
||||||
}
|
}
|
||||||
return &res, nil
|
return &res, nil
|
||||||
}
|
}
|
||||||
@ -246,6 +249,17 @@ func replaceInterestingFields(allFields *model.GetFieldsResponse, queryTokens []
|
|||||||
return queryTokens, nil
|
return queryTokens, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CheckIfPrevousPaginateAndModifyOrder(params *model.LogsFilterParams) (isPaginatePrevious bool) {
|
||||||
|
if params.IdGt != "" && params.OrderBy == TIMESTAMP && params.Order == DESC {
|
||||||
|
isPaginatePrevious = true
|
||||||
|
params.Order = ASC
|
||||||
|
} else if params.IdLT != "" && params.OrderBy == TIMESTAMP && params.Order == ASC {
|
||||||
|
isPaginatePrevious = true
|
||||||
|
params.Order = DESC
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func GenerateSQLWhere(allFields *model.GetFieldsResponse, params *model.LogsFilterParams) (string, error) {
|
func GenerateSQLWhere(allFields *model.GetFieldsResponse, params *model.LogsFilterParams) (string, error) {
|
||||||
var tokens []string
|
var tokens []string
|
||||||
var err error
|
var err error
|
||||||
@ -277,15 +291,15 @@ func GenerateSQLWhere(allFields *model.GetFieldsResponse, params *model.LogsFilt
|
|||||||
}
|
}
|
||||||
filterTokens = append(filterTokens, filter)
|
filterTokens = append(filterTokens, filter)
|
||||||
}
|
}
|
||||||
if params.IdStart != "" {
|
if params.IdGt != "" {
|
||||||
filter := fmt.Sprintf("id > '%v' ", params.IdStart)
|
filter := fmt.Sprintf("id > '%v' ", params.IdGt)
|
||||||
if len(filterTokens) > 0 {
|
if len(filterTokens) > 0 {
|
||||||
filter = "and " + filter
|
filter = "and " + filter
|
||||||
}
|
}
|
||||||
filterTokens = append(filterTokens, filter)
|
filterTokens = append(filterTokens, filter)
|
||||||
}
|
}
|
||||||
if params.IdEnd != "" {
|
if params.IdLT != "" {
|
||||||
filter := fmt.Sprintf("id < '%v' ", params.IdEnd)
|
filter := fmt.Sprintf("id < '%v' ", params.IdLT)
|
||||||
if len(filterTokens) > 0 {
|
if len(filterTokens) > 0 {
|
||||||
filter = "and " + filter
|
filter = "and " + filter
|
||||||
}
|
}
|
||||||
|
@ -208,6 +208,69 @@ func TestReplaceInterestingFields(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var previousPaginateTestCases = []struct {
|
||||||
|
Name string
|
||||||
|
Filter model.LogsFilterParams
|
||||||
|
IsPaginatePrev bool
|
||||||
|
Order string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
Name: "empty",
|
||||||
|
Filter: model.LogsFilterParams{},
|
||||||
|
IsPaginatePrev: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "next ordery by asc",
|
||||||
|
Filter: model.LogsFilterParams{
|
||||||
|
OrderBy: TIMESTAMP,
|
||||||
|
Order: ASC,
|
||||||
|
IdGt: "myid",
|
||||||
|
},
|
||||||
|
IsPaginatePrev: false,
|
||||||
|
Order: ASC,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "next ordery by desc",
|
||||||
|
Filter: model.LogsFilterParams{
|
||||||
|
OrderBy: TIMESTAMP,
|
||||||
|
Order: DESC,
|
||||||
|
IdLT: "myid",
|
||||||
|
},
|
||||||
|
IsPaginatePrev: false,
|
||||||
|
Order: DESC,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "prev ordery by desc",
|
||||||
|
Filter: model.LogsFilterParams{
|
||||||
|
OrderBy: TIMESTAMP,
|
||||||
|
Order: DESC,
|
||||||
|
IdGt: "myid",
|
||||||
|
},
|
||||||
|
IsPaginatePrev: true,
|
||||||
|
Order: ASC,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "prev ordery by asc",
|
||||||
|
Filter: model.LogsFilterParams{
|
||||||
|
OrderBy: TIMESTAMP,
|
||||||
|
Order: ASC,
|
||||||
|
IdLT: "myid",
|
||||||
|
},
|
||||||
|
IsPaginatePrev: true,
|
||||||
|
Order: DESC,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCheckIfPrevousPaginateAndModifyOrder(t *testing.T) {
|
||||||
|
for _, test := range previousPaginateTestCases {
|
||||||
|
Convey(test.Name, t, func() {
|
||||||
|
isPrevPaginate := CheckIfPrevousPaginateAndModifyOrder(&test.Filter)
|
||||||
|
So(isPrevPaginate, ShouldEqual, test.IsPaginatePrev)
|
||||||
|
So(test.Order, ShouldEqual, test.Filter.Order)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestGenerateSQLQuery(t *testing.T) {
|
func TestGenerateSQLQuery(t *testing.T) {
|
||||||
allFields := model.GetFieldsResponse{
|
allFields := model.GetFieldsResponse{
|
||||||
Selected: []model.LogField{
|
Selected: []model.LogField{
|
||||||
@ -233,7 +296,7 @@ func TestGenerateSQLQuery(t *testing.T) {
|
|||||||
idEnd := "2BsKG6tRpFWjYMcWsAGKfSxoQdU"
|
idEnd := "2BsKG6tRpFWjYMcWsAGKfSxoQdU"
|
||||||
sqlWhere := "timestamp >= '1657689292000' and timestamp <= '1657689294000' and id > '2BsKLKv8cZrLCn6rkOcRGkdjBdM' and id < '2BsKG6tRpFWjYMcWsAGKfSxoQdU' and id < 100 and id > 50 and attributes_int64_value[indexOf(attributes_int64_key, 'code')] <= 500 and attributes_int64_value[indexOf(attributes_int64_key, 'code')] >= 400 "
|
sqlWhere := "timestamp >= '1657689292000' and timestamp <= '1657689294000' and id > '2BsKLKv8cZrLCn6rkOcRGkdjBdM' and id < '2BsKG6tRpFWjYMcWsAGKfSxoQdU' and id < 100 and id > 50 and attributes_int64_value[indexOf(attributes_int64_key, 'code')] <= 500 and attributes_int64_value[indexOf(attributes_int64_key, 'code')] >= 400 "
|
||||||
Convey("testGenerateSQL", t, func() {
|
Convey("testGenerateSQL", t, func() {
|
||||||
res, _ := GenerateSQLWhere(&allFields, &model.LogsFilterParams{Query: query, TimestampStart: tsStart, TimestampEnd: tsEnd, IdStart: idStart, IdEnd: idEnd})
|
res, _ := GenerateSQLWhere(&allFields, &model.LogsFilterParams{Query: query, TimestampStart: tsStart, TimestampEnd: tsEnd, IdGt: idStart, IdLT: idEnd})
|
||||||
So(res, ShouldEqual, sqlWhere)
|
So(res, ShouldEqual, sqlWhere)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -591,7 +591,7 @@ func parseTTLParams(r *http.Request) (*model.TTLParams, error) {
|
|||||||
|
|
||||||
// Validate the type parameter
|
// Validate the type parameter
|
||||||
if typeTTL != constants.TraceTTL && typeTTL != constants.MetricsTTL && typeTTL != constants.LogsTTL {
|
if typeTTL != constants.TraceTTL && typeTTL != constants.MetricsTTL && typeTTL != constants.LogsTTL {
|
||||||
return nil, fmt.Errorf("type param should be metrics|traces, got %v", typeTTL)
|
return nil, fmt.Errorf("type param should be metrics|traces|logs, got %v", typeTTL)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate the TTL duration.
|
// Validate the TTL duration.
|
||||||
@ -630,7 +630,7 @@ func parseGetTTL(r *http.Request) (*model.GetTTLParams, error) {
|
|||||||
} else {
|
} else {
|
||||||
// Validate the type parameter
|
// Validate the type parameter
|
||||||
if typeTTL != constants.TraceTTL && typeTTL != constants.MetricsTTL && typeTTL != constants.LogsTTL {
|
if typeTTL != constants.TraceTTL && typeTTL != constants.MetricsTTL && typeTTL != constants.LogsTTL {
|
||||||
return nil, fmt.Errorf("type param should be metrics|traces, got %v", typeTTL)
|
return nil, fmt.Errorf("type param should be metrics|traces|logs, got %v", typeTTL)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -337,8 +337,8 @@ type LogsFilterParams struct {
|
|||||||
Query string `json:"q"`
|
Query string `json:"q"`
|
||||||
TimestampStart uint64 `json:"timestampStart"`
|
TimestampStart uint64 `json:"timestampStart"`
|
||||||
TimestampEnd uint64 `json:"timestampEnd"`
|
TimestampEnd uint64 `json:"timestampEnd"`
|
||||||
IdStart string `json:"idStart"`
|
IdGt string `json:"idGt"`
|
||||||
IdEnd string `json:"idEnd"`
|
IdLT string `json:"idLt"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type LogsAggregateParams struct {
|
type LogsAggregateParams struct {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user