Like Prometheus, but for logs.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
loki/pkg/analytics/stats_test.go

176 lines
4.3 KiB

package analytics
import (
"context"
"runtime"
"sync"
"testing"
"time"
"github.com/google/uuid"
jsoniter "github.com/json-iterator/go"
"github.com/stretchr/testify/require"
"golang.org/x/sync/errgroup"
"github.com/grafana/loki/v3/pkg/util/build"
)
func Test_BuildReport(t *testing.T) {
now := time.Now()
seed := &ClusterSeed{
UID: uuid.New().String(),
CreatedAt: now,
}
Edition("non-OSS")
Edition("OSS")
Target("distributor")
Target("compactor")
NewString("compression").Set("snappy")
NewString("compression").Set("lz4")
NewInt("compression_ratio").Set(50)
NewInt("compression_ratio").Set(100)
NewFloat("size_mb").Set(100.1)
NewFloat("size_mb").Set(200.1)
NewCounter("lines_written").Inc(200)
s := NewStatistics("query_throughput")
s.Record(25)
s = NewStatistics("query_throughput")
s.Record(300)
s.Record(5)
w := NewWordCounter("active_tenants")
w.Add("buz")
w = NewWordCounter("active_tenants")
w.Add("foo")
w.Add("bar")
w.Add("foo")
r := buildReport(seed, now.Add(time.Hour))
require.Equal(t, r.Arch, runtime.GOARCH)
require.Equal(t, r.Os, runtime.GOOS)
require.Equal(t, r.PrometheusVersion, build.GetVersion())
require.Equal(t, r.Edition, "OSS")
require.Equal(t, r.Target, "compactor")
require.Equal(t, r.Metrics["num_cpu"], runtime.NumCPU())
// Don't check num_goroutine because it could have changed since the report was created.
require.Equal(t, r.Metrics["compression"], "lz4")
require.Equal(t, r.Metrics["compression_ratio"], int64(100))
require.Equal(t, r.Metrics["size_mb"], 200.1)
require.Equal(t, r.Metrics["lines_written"].(map[string]interface{})["total"], int64(200))
require.Equal(t, r.Metrics["query_throughput"].(map[string]interface{})["min"], float64(5))
require.Equal(t, r.Metrics["query_throughput"].(map[string]interface{})["max"], float64(300))
require.Equal(t, r.Metrics["query_throughput"].(map[string]interface{})["count"], int64(3))
require.Equal(t, r.Metrics["query_throughput"].(map[string]interface{})["avg"], float64(25+300+5)/3)
require.Equal(t, r.Metrics["active_tenants"], int64(3))
out, _ := jsoniter.MarshalIndent(r, "", " ")
t.Log(string(out))
}
func TestCounterRace(t *testing.T) {
counterName := "test_counter_" + t.TempDir()
g, _ := errgroup.WithContext(context.Background())
g.Go(func() error {
c := NewCounter(counterName)
c.Inc(100)
return nil
})
g.Go(func() error {
c := NewCounter(counterName)
c.Inc(200)
return nil
})
require.NoError(t, g.Wait())
require.Equal(t, NewCounter(counterName).total.Load(), int64(300))
}
func TestCounter(t *testing.T) {
c := NewCounter("test_counter")
c.Inc(100)
c.Inc(200)
c.Inc(300)
time.Sleep(1 * time.Second)
c.updateRate()
v := c.Value()
require.Equal(t, int64(600), v["total"])
require.GreaterOrEqual(t, v["rate"], float64(590))
c.reset()
require.Equal(t, int64(0), c.Value()["total"])
require.Equal(t, float64(0), c.Value()["rate"])
}
func TestStatistic(t *testing.T) {
s := NewStatistics("test_stats")
s.Record(100)
s.Record(200)
s.Record(300)
v := s.Value()
require.Equal(t, float64(100), v["min"])
require.Equal(t, float64(300), v["max"])
require.Equal(t, int64(3), v["count"])
require.Equal(t, float64(100+200+300)/3, v["avg"])
require.Equal(t, float64(81.64965809277261), v["stddev"])
require.Equal(t, float64(6666.666666666667), v["stdvar"])
}
func TestWordCounter(t *testing.T) {
w := NewWordCounter("test_words_count")
var wg sync.WaitGroup
for i := 0; i < 100; i++ {
wg.Add(1)
go func() {
defer wg.Done()
w.Add("foo")
w.Add("bar")
w.Add("foo")
}()
}
wg.Wait()
require.Equal(t, int64(2), w.Value())
}
func TestPanics(t *testing.T) {
require.Panics(t, func() {
NewStatistics("panicstats")
NewWordCounter("panicstats")
})
require.Panics(t, func() {
NewWordCounter("panicwordcounter")
NewCounter("panicwordcounter")
})
require.Panics(t, func() {
NewCounter("paniccounter")
NewStatistics("paniccounter")
})
require.Panics(t, func() {
NewFloat("panicfloat")
NewInt("panicfloat")
})
require.Panics(t, func() {
NewInt("panicint")
NewString("panicint")
})
require.Panics(t, func() {
NewString("panicstring")
NewFloat("panicstring")
})
require.Panics(t, func() {
NewFloat(targetKey)
Target("new target")
})
require.Panics(t, func() {
NewFloat(editionKey)
Edition("new edition")
})
}