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/querier/querier.go

102 lines
2.3 KiB

package querier
import (
"context"
"flag"
"time"
cortex_client "github.com/weaveworks/cortex/pkg/ingester/client"
"github.com/weaveworks/cortex/pkg/ring"
"google.golang.org/grpc/health/grpc_health_v1"
"github.com/grafana/logish/pkg/ingester/client"
"github.com/grafana/logish/pkg/logproto"
)
type Config struct {
RemoteTimeout time.Duration
ClientConfig client.Config
}
func (cfg *Config) RegisterFlags(f *flag.FlagSet) {
f.DurationVar(&cfg.RemoteTimeout, "querier.remote-timeout", 10*time.Second, "")
cfg.ClientConfig.RegisterFlags(f)
}
type Querier struct {
cfg Config
ring ring.ReadRing
pool *cortex_client.IngesterPool
}
func New(cfg Config, ring ring.ReadRing) (*Querier, error) {
factory := func(addr string) (grpc_health_v1.HealthClient, error) {
return client.New(cfg.ClientConfig, addr)
}
return &Querier{
cfg: cfg,
ring: ring,
pool: cortex_client.NewIngesterPool(factory, cfg.RemoteTimeout),
}, nil
}
func (q *Querier) Query(req *logproto.QueryRequest, queryServer logproto.Querier_QueryServer) error {
return q.forAllIngesters(func(client logproto.QuerierClient) error {
_, err := client.Query(queryServer.Context(), req)
if err != nil {
return err
}
// TODO: a heap to in-order merge and dedupe results
return nil
})
}
// forAllIngesters runs f, in parallel, for all ingesters
// TODO taken from Cortex, see if we can refactor out an usable interface.
func (q *Querier) forAllIngesters(f func(logproto.QuerierClient) error) error {
replicationSet, err := q.ring.GetAll()
if err != nil {
return err
}
errs := make(chan error)
for _, ingester := range replicationSet.Ingesters {
go func(ingester *ring.IngesterDesc) {
client, err := q.pool.GetClientFor(ingester.Addr)
if err != nil {
errs <- err
return
}
errs <- f(client.(logproto.QuerierClient))
}(ingester)
}
var lastErr error
numErrs := 0
for range replicationSet.Ingesters {
select {
case err := <-errs:
if err != nil {
lastErr = err
numErrs++
}
}
}
if numErrs > replicationSet.MaxErrors {
return lastErr
}
return nil
}
// Check implements the grpc healthcheck
func (*Querier) Check(ctx context.Context, req *grpc_health_v1.HealthCheckRequest) (*grpc_health_v1.HealthCheckResponse, error) {
return &grpc_health_v1.HealthCheckResponse{Status: grpc_health_v1.HealthCheckResponse_SERVING}, nil
}