Skip to content

The pagination results order of the logs is incorrect #9705

Open
@honganan

Description

@honganan

Describe the bug
query-frontend split query and send to queriers, then collect the response data and merge, then return the first limit lines sort by timestamp.

However, In some situations, if the total number of log lines returned by queriers are bigger than the limit, the last returned result may not be the first limit lines. I think problem comes from the heap sort (not sure if it's api usage problem).

I found this in our production environment, after research I create a simple test case below which can reproduce it easier.

To Reproduce

  1. Below is a test case, put it in codec_test.go#Test_codec_MergeResponse and run it. It would fails.
{
	"loki backward special",
	[]queryrangebase.Response{
		&LokiResponse{
			Status:    loghttp.QueryStatusSuccess,
			Direction: logproto.BACKWARD,
			Limit:     10,
			Version:   1,
			Data: LokiData{
				ResultType: loghttp.ResultTypeStream,
				Result: []logproto.Stream{
					{
						Labels: `{foo="bar", level="debug"}`,
						Entries: []logproto.Entry{
							{Timestamp: time.Unix(0, 11), Line: "11"},
						},
					},
					{
						Labels: `{foo="bar", level="error"}`,
						Entries: []logproto.Entry{
							{Timestamp: time.Unix(0, 12), Line: "12"},
							{Timestamp: time.Unix(0, 10), Line: "10"},
							{Timestamp: time.Unix(0, 9), Line: "9"},
							{Timestamp: time.Unix(0, 8), Line: "8"},
						},
					},
				},
			},
		},
		&LokiResponse{
			Status:    loghttp.QueryStatusSuccess,
			Direction: logproto.BACKWARD,
			Limit:     10,
			Version:   1,
			Data: LokiData{
				ResultType: loghttp.ResultTypeStream,
				Result: []logproto.Stream{
					{
						Labels: `{foo="bar", level="debug"}`,
						Entries: []logproto.Entry{
							{Timestamp: time.Unix(0, 6), Line: "6"},
						},
					},
					{
						Labels: `{foo="bar", level="error"}`,
						Entries: []logproto.Entry{
							{Timestamp: time.Unix(0, 7), Line: "7"},
							{Timestamp: time.Unix(0, 5), Line: "5"},
							{Timestamp: time.Unix(0, 4), Line: "4"},
						},
					},
				},
			},
		},
		&LokiResponse{
			Status:    loghttp.QueryStatusSuccess,
			Direction: logproto.BACKWARD,
			Limit:     10,
			Version:   1,
			Data: LokiData{
				ResultType: loghttp.ResultTypeStream,
				Result: []logproto.Stream{
					{
						Labels: `{foo="bar", level="debug"}`,
						Entries: []logproto.Entry{
							{Timestamp: time.Unix(0, 2), Line: "2"},
							{Timestamp: time.Unix(0, 1), Line: "1"},
						},
					},
					{
						Labels: `{foo="bar", level="error"}`,
						Entries: []logproto.Entry{
							{Timestamp: time.Unix(0, 3), Line: "3"},
						},
					},
				},
			},
		},
	},
	&LokiResponse{
		Status:     loghttp.QueryStatusSuccess,
		Direction:  logproto.BACKWARD,
		Limit:      10,
		Version:    1,
		Statistics: stats.Result{Summary: stats.Summary{Splits: 3}},
		Data: LokiData{
			ResultType: loghttp.ResultTypeStream,
			Result: []logproto.Stream{
				{
					Labels: `{foo="bar", level="error"}`,
					Entries: []logproto.Entry{
						{Timestamp: time.Unix(0, 12), Line: "12"},
						{Timestamp: time.Unix(0, 10), Line: "10"},
						{Timestamp: time.Unix(0, 9), Line: "9"},
						{Timestamp: time.Unix(0, 8), Line: "8"},
						{Timestamp: time.Unix(0, 7), Line: "7"},
						{Timestamp: time.Unix(0, 5), Line: "5"},
						{Timestamp: time.Unix(0, 4), Line: "4"},
						{Timestamp: time.Unix(0, 3), Line: "3"},
					},
				},
				{
					Labels: `{foo="bar", level="debug"}`,
					Entries: []logproto.Entry{
						{Timestamp: time.Unix(0, 11), Line: "11"},
						{Timestamp: time.Unix(0, 6), Line: "6"},
					},
				},
			},
		},
	},
	false,
},

Expected behavior
There are 12 lines in total (nanoseconds 1 ~ 12), and limit is 10, expect return 12 ~ 3.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions