Skip to content

Commit

Permalink
support series API in logcli
Browse files Browse the repository at this point in the history
Signed-off-by: yeya24 <yb532204897@gmail.com>

add changelog

Signed-off-by: yeya24 <yb532204897@gmail.com>
  • Loading branch information
yeya24 committed Mar 31, 2020
1 parent 733b246 commit b6f3a48
Show file tree
Hide file tree
Showing 8 changed files with 111 additions and 22 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
* [1572](https://github.com/grafana/loki/pull/1572) **owen-d**: Introduces the `querier.query-ingesters-within` flag and associated yaml config. When enabled, queries for a time range that do not overlap this lookback interval will not be sent to the ingesters.
* [1558](https://github.com/grafana/loki/pull/1558) **owen-d**: Introduces `ingester.max-chunk-age` which specifies the maximum chunk age before it's cut.
* [1565](https://github.com/grafana/loki/pull/1565) **owen-d**: The query frontend's `split_queries_by_interval` can now be specified as an override
* [1861](https://github.com/grafana/loki/pull/1565) **yeya24**: Support series command in logcli

## 1.3.0 (2020-01-16)

Expand Down
70 changes: 51 additions & 19 deletions cmd/logcli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ import (

"github.com/prometheus/common/config"
"github.com/prometheus/common/version"
"gopkg.in/alecthomas/kingpin.v2"

_ "github.com/grafana/loki/pkg/build"
"github.com/grafana/loki/pkg/logcli/client"
"github.com/grafana/loki/pkg/logcli/labelquery"
"github.com/grafana/loki/pkg/logcli/output"
"github.com/grafana/loki/pkg/logcli/query"

"gopkg.in/alecthomas/kingpin.v2"
"github.com/grafana/loki/pkg/logcli/seriesquery"
)

var (
Expand Down Expand Up @@ -72,6 +72,9 @@ https://github.com/grafana/loki/blob/master/docs/logql.md`)

labelsCmd = app.Command("labels", "Find values for a given label.")
labelName = labelsCmd.Arg("label", "The name of the label.").HintAction(hintActionLabelNames).String()

seriesCmd = app.Command("series", "Run series query.")
seriesQuery = newSeriesQuery(seriesCmd)
)

func main() {
Expand Down Expand Up @@ -122,6 +125,8 @@ func main() {
q := newLabelQuery(*labelName, *quiet)

q.DoLabels(queryClient)
case seriesCmd.FullCommand():
seriesQuery.DoSeries(queryClient)
}
}

Expand Down Expand Up @@ -165,49 +170,76 @@ func newLabelQuery(labelName string, quiet bool) *labelquery.LabelQuery {
}
}

func newSeriesQuery(cmd *kingpin.CmdClause) *seriesquery.SeriesQuery {
// calculate series range from cli params
var from, to string
var since time.Duration

q := &seriesquery.SeriesQuery{}

// executed after all command flags are parsed
cmd.Action(func(c *kingpin.ParseContext) error {

defaultEnd := time.Now()
defaultStart := defaultEnd.Add(-since)

q.Start = mustParse(from, defaultStart)
q.End = mustParse(to, defaultEnd)
q.Quiet = *quiet
return nil
})

cmd.Flag("since", "Lookback window.").Default("1h").DurationVar(&since)
cmd.Flag("from", "Start looking for logs at this absolute time (inclusive)").StringVar(&from)
cmd.Flag("to", "Stop looking for logs at this absolute time (exclusive)").StringVar(&to)
cmd.Flag("match", "eg '{foo=\"bar\",baz=~\".*blip\"}'").Required().StringsVar(&q.Matchers)

return q
}

func newQuery(instant bool, cmd *kingpin.CmdClause) *query.Query {
// calculcate query range from cli params
// calculate query range from cli params
var now, from, to string
var since time.Duration

query := &query.Query{}
q := &query.Query{}

// executed after all command flags are parsed
cmd.Action(func(c *kingpin.ParseContext) error {

if instant {
query.SetInstant(mustParse(now, time.Now()))
q.SetInstant(mustParse(now, time.Now()))
} else {
defaultEnd := time.Now()
defaultStart := defaultEnd.Add(-since)

query.Start = mustParse(from, defaultStart)
query.End = mustParse(to, defaultEnd)
q.Start = mustParse(from, defaultStart)
q.End = mustParse(to, defaultEnd)
}
query.Quiet = *quiet
q.Quiet = *quiet
return nil
})

cmd.Flag("limit", "Limit on number of entries to print.").Default("30").IntVar(&query.Limit)
cmd.Flag("limit", "Limit on number of entries to print.").Default("30").IntVar(&q.Limit)
if instant {
cmd.Arg("query", "eg 'rate({foo=\"bar\"} |~ \".*error.*\" [5m])'").Required().StringVar(&query.QueryString)
cmd.Arg("query", "eg 'rate({foo=\"bar\"} |~ \".*error.*\" [5m])'").Required().StringVar(&q.QueryString)
cmd.Flag("now", "Time at which to execute the instant query.").StringVar(&now)
} else {
cmd.Arg("query", "eg '{foo=\"bar\",baz=~\".*blip\"} |~ \".*error.*\"'").Required().StringVar(&query.QueryString)
cmd.Arg("query", "eg '{foo=\"bar\",baz=~\".*blip\"} |~ \".*error.*\"'").Required().StringVar(&q.QueryString)
cmd.Flag("since", "Lookback window.").Default("1h").DurationVar(&since)
cmd.Flag("from", "Start looking for logs at this absolute time (inclusive)").StringVar(&from)
cmd.Flag("to", "Stop looking for logs at this absolute time (exclusive)").StringVar(&to)
cmd.Flag("step", "Query resolution step width").DurationVar(&query.Step)
cmd.Flag("step", "Query resolution step width").DurationVar(&q.Step)
}

cmd.Flag("forward", "Scan forwards through logs.").Default("false").BoolVar(&query.Forward)
cmd.Flag("no-labels", "Do not print any labels").Default("false").BoolVar(&query.NoLabels)
cmd.Flag("exclude-label", "Exclude labels given the provided key during output.").StringsVar(&query.IgnoreLabelsKey)
cmd.Flag("include-label", "Include labels given the provided key during output.").StringsVar(&query.ShowLabelsKey)
cmd.Flag("labels-length", "Set a fixed padding to labels").Default("0").IntVar(&query.FixedLabelsLen)
cmd.Flag("store-config", "Execute the current query using a configured storage from a given Loki configuration file.").Default("").StringVar(&query.LocalConfig)
cmd.Flag("forward", "Scan forwards through logs.").Default("false").BoolVar(&q.Forward)
cmd.Flag("no-labels", "Do not print any labels").Default("false").BoolVar(&q.NoLabels)
cmd.Flag("exclude-label", "Exclude labels given the provided key during output.").StringsVar(&q.IgnoreLabelsKey)
cmd.Flag("include-label", "Include labels given the provided key during output.").StringsVar(&q.ShowLabelsKey)
cmd.Flag("labels-length", "Set a fixed padding to labels").Default("0").IntVar(&q.FixedLabelsLen)
cmd.Flag("store-config", "Execute the current query using a configured storage from a given Loki configuration file.").Default("").StringVar(&q.LocalConfig)

return query
return q
}

func mustParse(t string, defaultTime time.Time) time.Time {
Expand Down
2 changes: 1 addition & 1 deletion pkg/ingester/flush.go
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ func (i *Ingester) flushChunks(ctx context.Context, fp model.Fingerprint, labelP
return err
}

// Record statistsics only when actual put request did not return error.
// Record statistics only when actual put request did not return error.
sizePerTenant := chunkSizePerTenant.WithLabelValues(userID)
countPerTenant := chunksPerTenant.WithLabelValues(userID)
for i, wc := range wireChunks {
Expand Down
14 changes: 14 additions & 0 deletions pkg/logcli/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const (
queryRangePath = "/loki/api/v1/query_range"
labelsPath = "/loki/api/v1/labels"
labelValuesPath = "/loki/api/v1/label/%s/values"
seriesPath = "/loki/api/v1/series"
tailPath = "/loki/api/v1/tail?query=%s&delay_for=%d&limit=%d&start=%d"
)

Expand Down Expand Up @@ -89,6 +90,19 @@ func (c *Client) ListLabelValues(name string, quiet bool) (*loghttp.LabelRespons
return &labelResponse, nil
}

func (c *Client) Series(matchers []string, from, through time.Time, quiet bool) (*loghttp.SeriesResponse, error) {
params := util.NewQueryStringBuilder()
params.SetInt("start", from.UnixNano())
params.SetInt("end", through.UnixNano())
params.SetStringArray("match", matchers)

var seriesResponse loghttp.SeriesResponse
if err := c.doRequest(params.EncodeWithPath(seriesPath), quiet, &seriesResponse); err != nil {
return nil, err
}
return &seriesResponse, nil
}

func (c *Client) doQuery(path string, quiet bool) (*loghttp.QueryResponse, error) {
var err error
var r loghttp.QueryResponse
Expand Down
2 changes: 1 addition & 1 deletion pkg/logcli/labelquery/labels.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
"github.com/grafana/loki/pkg/loghttp"
)

// LabelQuery contains all necessary fields to execute label queries and print out the resutls
// LabelQuery contains all necessary fields to execute label queries and print out the results
type LabelQuery struct {
LabelName string
Quiet bool
Expand Down
36 changes: 36 additions & 0 deletions pkg/logcli/seriesquery/series.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package seriesquery

import (
"fmt"
"log"
"time"

"github.com/grafana/loki/pkg/logcli/client"
"github.com/grafana/loki/pkg/loghttp"
)

// SeriesQuery contains all necessary fields to execute label queries and print out the results
type SeriesQuery struct {
Matchers []string
Start time.Time
End time.Time
Quiet bool
}

// DoSeries prints out series results
func (q *SeriesQuery) DoSeries(c *client.Client) {
values := q.GetSeries(c)

for _, value := range values {
fmt.Println(value)
}
}

// GetSeries returns an array of label sets
func (q *SeriesQuery) GetSeries(c *client.Client) []loghttp.LabelSet {
seriesResponse, err := c.Series(q.Matchers, q.Start, q.End, q.Quiet)
if err != nil {
log.Fatalf("Error doing request: %+v", err)
}
return seriesResponse.Data
}
2 changes: 1 addition & 1 deletion pkg/loghttp/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ func Match(xs []string) ([][]*labels.Matcher, error) {
}

// defaultQueryRangeStep returns the default step used in the query range API,
// which is dinamically calculated based on the time range
// which is dynamically calculated based on the time range
func defaultQueryRangeStep(start time.Time, end time.Time) int {
return int(math.Max(math.Floor(end.Sub(start).Seconds()/250), 1))
}
Expand Down
6 changes: 6 additions & 0 deletions pkg/util/query_string_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ func (b *QueryStringBuilder) SetString(name, value string) {
b.values.Set(name, value)
}

func (b *QueryStringBuilder) SetStringArray(name string, values []string) {
for _, v := range values {
b.values.Add(name, v)
}
}

func (b *QueryStringBuilder) SetInt(name string, value int64) {
b.SetString(name, strconv.FormatInt(value, 10))
}
Expand Down

0 comments on commit b6f3a48

Please sign in to comment.