|
|
|
|
@ -13,6 +13,7 @@ import ( |
|
|
|
|
"time" |
|
|
|
|
|
|
|
|
|
"github.com/dustin/go-humanize" |
|
|
|
|
"github.com/prometheus/prometheus/pkg/labels" |
|
|
|
|
"github.com/stretchr/testify/assert" |
|
|
|
|
"github.com/stretchr/testify/require" |
|
|
|
|
|
|
|
|
|
@ -35,8 +36,16 @@ var testEncoding = []Encoding{ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var ( |
|
|
|
|
testBlockSize = 256 * 1024 |
|
|
|
|
testTargetSize = 1500 * 1024 |
|
|
|
|
testBlockSize = 256 * 1024 |
|
|
|
|
testTargetSize = 1500 * 1024 |
|
|
|
|
noopStreamPipeline = log.NewNoopPipeline().ForStream(labels.Labels{}) |
|
|
|
|
countExtractor = func() log.StreamSampleExtractor { |
|
|
|
|
ex, err := log.NewLineSampleExtractor(log.CountExtractor, nil, nil, false, false) |
|
|
|
|
if err != nil { |
|
|
|
|
panic(err) |
|
|
|
|
} |
|
|
|
|
return ex.ForStream(labels.Labels{}) |
|
|
|
|
}() |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
func TestBlocksInclusive(t *testing.T) { |
|
|
|
|
@ -114,7 +123,7 @@ func TestBlock(t *testing.T) { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
it, err := chk.Iterator(context.Background(), time.Unix(0, 0), time.Unix(0, math.MaxInt64), logproto.FORWARD, nil, logql.NoopPipeline) |
|
|
|
|
it, err := chk.Iterator(context.Background(), time.Unix(0, 0), time.Unix(0, math.MaxInt64), logproto.FORWARD, noopStreamPipeline) |
|
|
|
|
require.NoError(t, err) |
|
|
|
|
|
|
|
|
|
idx := 0 |
|
|
|
|
@ -129,7 +138,7 @@ func TestBlock(t *testing.T) { |
|
|
|
|
require.NoError(t, it.Close()) |
|
|
|
|
require.Equal(t, len(cases), idx) |
|
|
|
|
|
|
|
|
|
sampleIt := chk.SampleIterator(context.Background(), time.Unix(0, 0), time.Unix(0, math.MaxInt64), nil, log.CountExtractor.ToSampleExtractor(nil, false, false)) |
|
|
|
|
sampleIt := chk.SampleIterator(context.Background(), time.Unix(0, 0), time.Unix(0, math.MaxInt64), countExtractor) |
|
|
|
|
idx = 0 |
|
|
|
|
for sampleIt.Next() { |
|
|
|
|
s := sampleIt.Sample() |
|
|
|
|
@ -144,7 +153,7 @@ func TestBlock(t *testing.T) { |
|
|
|
|
require.Equal(t, len(cases), idx) |
|
|
|
|
|
|
|
|
|
t.Run("bounded-iteration", func(t *testing.T) { |
|
|
|
|
it, err := chk.Iterator(context.Background(), time.Unix(0, 3), time.Unix(0, 7), logproto.FORWARD, nil, logql.NoopPipeline) |
|
|
|
|
it, err := chk.Iterator(context.Background(), time.Unix(0, 3), time.Unix(0, 7), logproto.FORWARD, noopStreamPipeline) |
|
|
|
|
require.NoError(t, err) |
|
|
|
|
|
|
|
|
|
idx := 2 |
|
|
|
|
@ -177,7 +186,7 @@ func TestReadFormatV1(t *testing.T) { |
|
|
|
|
t.Fatal(err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
it, err := r.Iterator(context.Background(), time.Unix(0, 0), time.Unix(0, math.MaxInt64), logproto.FORWARD, nil, logql.NoopPipeline) |
|
|
|
|
it, err := r.Iterator(context.Background(), time.Unix(0, 0), time.Unix(0, math.MaxInt64), logproto.FORWARD, noopStreamPipeline) |
|
|
|
|
if err != nil { |
|
|
|
|
t.Fatal(err) |
|
|
|
|
} |
|
|
|
|
@ -204,7 +213,7 @@ func TestRoundtripV2(t *testing.T) { |
|
|
|
|
|
|
|
|
|
assertLines := func(c *MemChunk) { |
|
|
|
|
require.Equal(t, enc, c.Encoding()) |
|
|
|
|
it, err := c.Iterator(context.Background(), time.Unix(0, 0), time.Unix(0, math.MaxInt64), logproto.FORWARD, nil, logql.NoopPipeline) |
|
|
|
|
it, err := c.Iterator(context.Background(), time.Unix(0, 0), time.Unix(0, math.MaxInt64), logproto.FORWARD, noopStreamPipeline) |
|
|
|
|
if err != nil { |
|
|
|
|
t.Fatal(err) |
|
|
|
|
} |
|
|
|
|
@ -266,7 +275,7 @@ func TestSerialization(t *testing.T) { |
|
|
|
|
bc, err := NewByteChunk(byt, testBlockSize, testTargetSize) |
|
|
|
|
require.NoError(t, err) |
|
|
|
|
|
|
|
|
|
it, err := bc.Iterator(context.Background(), time.Unix(0, 0), time.Unix(0, math.MaxInt64), logproto.FORWARD, nil, logql.NoopPipeline) |
|
|
|
|
it, err := bc.Iterator(context.Background(), time.Unix(0, 0), time.Unix(0, math.MaxInt64), logproto.FORWARD, noopStreamPipeline) |
|
|
|
|
require.NoError(t, err) |
|
|
|
|
for i := 0; i < numSamples; i++ { |
|
|
|
|
require.True(t, it.Next()) |
|
|
|
|
@ -277,7 +286,7 @@ func TestSerialization(t *testing.T) { |
|
|
|
|
} |
|
|
|
|
require.NoError(t, it.Error()) |
|
|
|
|
|
|
|
|
|
sampleIt := bc.SampleIterator(context.Background(), time.Unix(0, 0), time.Unix(0, math.MaxInt64), nil, log.CountExtractor.ToSampleExtractor(nil, false, false)) |
|
|
|
|
sampleIt := bc.SampleIterator(context.Background(), time.Unix(0, 0), time.Unix(0, math.MaxInt64), countExtractor) |
|
|
|
|
for i := 0; i < numSamples; i++ { |
|
|
|
|
require.True(t, sampleIt.Next(), i) |
|
|
|
|
|
|
|
|
|
@ -320,7 +329,7 @@ func TestChunkFilling(t *testing.T) { |
|
|
|
|
|
|
|
|
|
require.Equal(t, int64(lines), i) |
|
|
|
|
|
|
|
|
|
it, err := chk.Iterator(context.Background(), time.Unix(0, 0), time.Unix(0, 100), logproto.FORWARD, nil, logql.NoopPipeline) |
|
|
|
|
it, err := chk.Iterator(context.Background(), time.Unix(0, 0), time.Unix(0, 100), logproto.FORWARD, noopStreamPipeline) |
|
|
|
|
require.NoError(t, err) |
|
|
|
|
i = 0 |
|
|
|
|
for it.Next() { |
|
|
|
|
@ -463,7 +472,7 @@ func TestChunkStats(t *testing.T) { |
|
|
|
|
expectedSize := (inserted * len(entry.Line)) + (inserted * 2 * binary.MaxVarintLen64) |
|
|
|
|
ctx := stats.NewContext(context.Background()) |
|
|
|
|
|
|
|
|
|
it, err := c.Iterator(ctx, first.Add(-time.Hour), entry.Timestamp.Add(time.Hour), logproto.BACKWARD, nil, logql.NoopPipeline) |
|
|
|
|
it, err := c.Iterator(ctx, first.Add(-time.Hour), entry.Timestamp.Add(time.Hour), logproto.BACKWARD, noopStreamPipeline) |
|
|
|
|
if err != nil { |
|
|
|
|
t.Fatal(err) |
|
|
|
|
} |
|
|
|
|
@ -492,7 +501,7 @@ func TestChunkStats(t *testing.T) { |
|
|
|
|
t.Fatal(err) |
|
|
|
|
} |
|
|
|
|
ctx = stats.NewContext(context.Background()) |
|
|
|
|
it, err = cb.Iterator(ctx, first.Add(-time.Hour), entry.Timestamp.Add(time.Hour), logproto.BACKWARD, nil, logql.NoopPipeline) |
|
|
|
|
it, err = cb.Iterator(ctx, first.Add(-time.Hour), entry.Timestamp.Add(time.Hour), logproto.BACKWARD, noopStreamPipeline) |
|
|
|
|
if err != nil { |
|
|
|
|
t.Fatal(err) |
|
|
|
|
} |
|
|
|
|
@ -540,7 +549,7 @@ func TestIteratorClose(t *testing.T) { |
|
|
|
|
} { |
|
|
|
|
c := NewMemChunk(enc, testBlockSize, testTargetSize) |
|
|
|
|
inserted := fillChunk(c) |
|
|
|
|
iter, err := c.Iterator(context.Background(), time.Unix(0, 0), time.Unix(0, inserted), logproto.BACKWARD, nil, logql.NoopPipeline) |
|
|
|
|
iter, err := c.Iterator(context.Background(), time.Unix(0, 0), time.Unix(0, inserted), logproto.BACKWARD, noopStreamPipeline) |
|
|
|
|
if err != nil { |
|
|
|
|
t.Fatal(err) |
|
|
|
|
} |
|
|
|
|
@ -591,7 +600,7 @@ func BenchmarkRead(b *testing.B) { |
|
|
|
|
for n := 0; n < b.N; n++ { |
|
|
|
|
for _, c := range chunks { |
|
|
|
|
// use forward iterator for benchmark -- backward iterator does extra allocations by keeping entries in memory
|
|
|
|
|
iterator, err := c.Iterator(context.Background(), time.Unix(0, 0), time.Now(), logproto.FORWARD, nil, logql.NoopPipeline) |
|
|
|
|
iterator, err := c.Iterator(context.Background(), time.Unix(0, 0), time.Now(), logproto.FORWARD, noopStreamPipeline) |
|
|
|
|
if err != nil { |
|
|
|
|
panic(err) |
|
|
|
|
} |
|
|
|
|
@ -616,7 +625,7 @@ func BenchmarkBackwardIterator(b *testing.B) { |
|
|
|
|
_ = fillChunk(c) |
|
|
|
|
b.ResetTimer() |
|
|
|
|
for n := 0; n < b.N; n++ { |
|
|
|
|
iterator, err := c.Iterator(context.Background(), time.Unix(0, 0), time.Now(), logproto.BACKWARD, nil, logql.NoopPipeline) |
|
|
|
|
iterator, err := c.Iterator(context.Background(), time.Unix(0, 0), time.Now(), logproto.BACKWARD, noopStreamPipeline) |
|
|
|
|
if err != nil { |
|
|
|
|
panic(err) |
|
|
|
|
} |
|
|
|
|
@ -637,7 +646,7 @@ func TestGenerateDataSize(t *testing.T) { |
|
|
|
|
bytesRead := uint64(0) |
|
|
|
|
for _, c := range chunks { |
|
|
|
|
// use forward iterator for benchmark -- backward iterator does extra allocations by keeping entries in memory
|
|
|
|
|
iterator, err := c.Iterator(context.TODO(), time.Unix(0, 0), time.Now(), logproto.FORWARD, nil, logql.NoopPipeline) |
|
|
|
|
iterator, err := c.Iterator(context.TODO(), time.Unix(0, 0), time.Now(), logproto.FORWARD, noopStreamPipeline) |
|
|
|
|
if err != nil { |
|
|
|
|
panic(err) |
|
|
|
|
} |
|
|
|
|
@ -671,7 +680,7 @@ func BenchmarkHeadBlockIterator(b *testing.B) { |
|
|
|
|
b.ResetTimer() |
|
|
|
|
|
|
|
|
|
for n := 0; n < b.N; n++ { |
|
|
|
|
iter := h.iterator(context.Background(), logproto.BACKWARD, 0, math.MaxInt64, nil, logql.NoopPipeline) |
|
|
|
|
iter := h.iterator(context.Background(), logproto.BACKWARD, 0, math.MaxInt64, noopStreamPipeline) |
|
|
|
|
|
|
|
|
|
for iter.Next() { |
|
|
|
|
_ = iter.Entry() |
|
|
|
|
@ -730,7 +739,7 @@ func TestMemChunk_IteratorBounds(t *testing.T) { |
|
|
|
|
c := createChunk() |
|
|
|
|
|
|
|
|
|
// testing headchunk
|
|
|
|
|
it, err := c.Iterator(context.Background(), tt.mint, tt.maxt, tt.direction, nil, logql.NoopPipeline) |
|
|
|
|
it, err := c.Iterator(context.Background(), tt.mint, tt.maxt, tt.direction, noopStreamPipeline) |
|
|
|
|
require.NoError(t, err) |
|
|
|
|
for i := range tt.expect { |
|
|
|
|
require.Equal(t, tt.expect[i], it.Next()) |
|
|
|
|
@ -739,7 +748,7 @@ func TestMemChunk_IteratorBounds(t *testing.T) { |
|
|
|
|
|
|
|
|
|
// testing chunk blocks
|
|
|
|
|
require.NoError(t, c.cut()) |
|
|
|
|
it, err = c.Iterator(context.Background(), tt.mint, tt.maxt, tt.direction, nil, logql.NoopPipeline) |
|
|
|
|
it, err = c.Iterator(context.Background(), tt.mint, tt.maxt, tt.direction, noopStreamPipeline) |
|
|
|
|
require.NoError(t, err) |
|
|
|
|
for i := range tt.expect { |
|
|
|
|
require.Equal(t, tt.expect[i], it.Next()) |
|
|
|
|
@ -758,7 +767,7 @@ func TestMemchunkLongLine(t *testing.T) { |
|
|
|
|
for i := 1; i <= 10; i++ { |
|
|
|
|
require.NoError(t, c.Append(&logproto.Entry{Timestamp: time.Unix(0, int64(i)), Line: strings.Repeat("e", 200000)})) |
|
|
|
|
} |
|
|
|
|
it, err := c.Iterator(context.Background(), time.Unix(0, 0), time.Unix(0, 100), logproto.FORWARD, nil, logql.NoopPipeline) |
|
|
|
|
it, err := c.Iterator(context.Background(), time.Unix(0, 0), time.Unix(0, 100), logproto.FORWARD, noopStreamPipeline) |
|
|
|
|
require.NoError(t, err) |
|
|
|
|
for i := 1; i <= 10; i++ { |
|
|
|
|
require.True(t, it.Next()) |
|
|
|
|
@ -777,3 +786,102 @@ func TestBytesWith(t *testing.T) { |
|
|
|
|
|
|
|
|
|
require.Equal(t, exp, out) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var streams = []logproto.Stream{} |
|
|
|
|
var series = []logproto.Series{} |
|
|
|
|
|
|
|
|
|
func BenchmarkBufferedIteratorLabels(b *testing.B) { |
|
|
|
|
c := NewMemChunk(EncSnappy, testBlockSize, testTargetSize) |
|
|
|
|
_ = fillChunk(c) |
|
|
|
|
labelsSet := []labels.Labels{ |
|
|
|
|
{ |
|
|
|
|
{Name: "cluster", Value: "us-central1"}, |
|
|
|
|
{Name: "stream", Value: "stdout"}, |
|
|
|
|
{Name: "filename", Value: "/var/log/pods/loki-prod_query-frontend-6894f97b98-89q2n_eac98024-f60f-44af-a46f-d099bc99d1e7/query-frontend/0.log"}, |
|
|
|
|
{Name: "namespace", Value: "loki-dev"}, |
|
|
|
|
{Name: "job", Value: "loki-prod/query-frontend"}, |
|
|
|
|
{Name: "container", Value: "query-frontend"}, |
|
|
|
|
{Name: "pod", Value: "query-frontend-6894f97b98-89q2n"}, |
|
|
|
|
}, |
|
|
|
|
{ |
|
|
|
|
{Name: "cluster", Value: "us-central2"}, |
|
|
|
|
{Name: "stream", Value: "stderr"}, |
|
|
|
|
{Name: "filename", Value: "/var/log/pods/loki-prod_querier-6894f97b98-89q2n_eac98024-f60f-44af-a46f-d099bc99d1e7/query-frontend/0.log"}, |
|
|
|
|
{Name: "namespace", Value: "loki-dev"}, |
|
|
|
|
{Name: "job", Value: "loki-prod/querier"}, |
|
|
|
|
{Name: "container", Value: "querier"}, |
|
|
|
|
{Name: "pod", Value: "querier-6894f97b98-89q2n"}, |
|
|
|
|
}, |
|
|
|
|
} |
|
|
|
|
for _, test := range []string{ |
|
|
|
|
`{app="foo"}`, |
|
|
|
|
`{app="foo"} != "foo"`, |
|
|
|
|
`{app="foo"} != "foo" | logfmt `, |
|
|
|
|
`{app="foo"} != "foo" | logfmt | duration > 10ms`, |
|
|
|
|
`{app="foo"} != "foo" | logfmt | duration > 10ms and component="tsdb"`, |
|
|
|
|
} { |
|
|
|
|
b.Run(test, func(b *testing.B) { |
|
|
|
|
b.ReportAllocs() |
|
|
|
|
expr, err := logql.ParseLogSelector(test) |
|
|
|
|
if err != nil { |
|
|
|
|
b.Fatal(err) |
|
|
|
|
} |
|
|
|
|
p, err := expr.Pipeline() |
|
|
|
|
if err != nil { |
|
|
|
|
b.Fatal(err) |
|
|
|
|
} |
|
|
|
|
var iters []iter.EntryIterator |
|
|
|
|
for _, lbs := range labelsSet { |
|
|
|
|
it, err := c.Iterator(context.Background(), time.Unix(0, 0), time.Now(), logproto.FORWARD, p.ForStream(lbs)) |
|
|
|
|
if err != nil { |
|
|
|
|
b.Fatal(err) |
|
|
|
|
} |
|
|
|
|
iters = append(iters, it) |
|
|
|
|
} |
|
|
|
|
b.ResetTimer() |
|
|
|
|
for n := 0; n < b.N; n++ { |
|
|
|
|
for _, it := range iters { |
|
|
|
|
for it.Next() { |
|
|
|
|
streams = append(streams, logproto.Stream{Labels: it.Labels(), Entries: []logproto.Entry{it.Entry()}}) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
streams = streams[:0] |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for _, test := range []string{ |
|
|
|
|
`rate({app="foo"}[1m])`, |
|
|
|
|
`sum by (cluster) (rate({app="foo"}[10s]))`, |
|
|
|
|
`sum by (cluster) (rate({app="foo"} != "foo" [10s]))`, |
|
|
|
|
`sum by (cluster) (rate({app="foo"} != "foo" | logfmt[10s]))`, |
|
|
|
|
`sum by (caller) (rate({app="foo"} != "foo" | logfmt[10s]))`, |
|
|
|
|
`sum by (cluster) (rate({app="foo"} != "foo" | logfmt | duration > 10ms[10s]))`, |
|
|
|
|
`sum by (cluster) (rate({app="foo"} != "foo" | logfmt | duration > 10ms and component="tsdb"[1m]))`, |
|
|
|
|
} { |
|
|
|
|
b.Run(test, func(b *testing.B) { |
|
|
|
|
b.ReportAllocs() |
|
|
|
|
expr, err := logql.ParseSampleExpr(test) |
|
|
|
|
if err != nil { |
|
|
|
|
b.Fatal(err) |
|
|
|
|
} |
|
|
|
|
ex, err := expr.Extractor() |
|
|
|
|
if err != nil { |
|
|
|
|
b.Fatal(err) |
|
|
|
|
} |
|
|
|
|
var iters []iter.SampleIterator |
|
|
|
|
for _, lbs := range labelsSet { |
|
|
|
|
iters = append(iters, c.SampleIterator(context.Background(), time.Unix(0, 0), time.Now(), ex.ForStream(lbs))) |
|
|
|
|
} |
|
|
|
|
b.ResetTimer() |
|
|
|
|
for n := 0; n < b.N; n++ { |
|
|
|
|
for _, it := range iters { |
|
|
|
|
for it.Next() { |
|
|
|
|
series = append(series, logproto.Series{Labels: it.Labels(), Samples: []logproto.Sample{it.Sample()}}) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
series = series[:0] |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|