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/logqlmodel/error.go

98 lines
2.6 KiB

package logqlmodel
import (
"errors"
"fmt"
"github.com/prometheus/prometheus/model/labels"
)
// Those errors are useful for comparing error returned by the engine.
// e.g. errors.Is(err,logqlmodel.ErrParse) let you know if this is a ast parsing error.
var (
ErrParse = errors.New("failed to parse the log query")
ErrPipeline = errors.New("failed execute pipeline")
ErrLimit = errors.New("limit reached while evaluating the query")
Loki: Add a limit for the [range] value on range queries (#8343) Signed-off-by: Edward Welch <edward.welch@grafana.com> **What this PR does / why we need it**: Loki does not currently split queries by time to a value smaller than what's in the [range] of a range query. Example ``` sum(rate({job="foo"}[2d])) ``` Imagine now this query being executed over a longer window of a few days with a step of something like 30m. Every step evaluation would query the last [2d] of data. There are use cases where this is desired, specifically if you force the step to match the value in the range, however what is more common is someone accidentally uses `[$__range]` in here instead of `[$__interval]` within Grafana and then sets the query time selector to a large value like 7 days. This PR adds a limit which will fail queries that set the [range] value higher than the configured limit. It's disabled by default. In the future it may be possible for Loki to perform splits within the [range] and remove the need for this limit, but until then this can be an important safeguard in clusters with a lot of data. **Which issue(s) this PR fixes**: Fixes #8746 **Special notes for your reviewer**: **Checklist** - [ ] Reviewed the [`CONTRIBUTING.md`](https://github.com/grafana/loki/blob/main/CONTRIBUTING.md) guide (**required**) - [ ] Documentation added - [ ] Tests updated - [ ] `CHANGELOG.md` updated - [ ] Changes that require user attention or interaction to upgrade are documented in `docs/sources/upgrading/_index.md` --------- Signed-off-by: Edward Welch <edward.welch@grafana.com> Co-authored-by: Karsten Jeschkies <karsten.jeschkies@grafana.com> Co-authored-by: Vladyslav Diachenko <82767850+vlad-diachenko@users.noreply.github.com>
2 years ago
ErrIntervalLimit = errors.New("[interval] value exceeds limit")
ErrBlocked = errors.New("query blocked by policy")
ErrParseMatchers = errors.New("only label matchers are supported")
ErrorLabel = "__error__"
PreserveErrorLabel = "__preserve_error__"
ErrorDetailsLabel = "__error_details__"
)
// ParseError is what is returned when we failed to parse.
type ParseError struct {
msg string
line, col int
}
func (p ParseError) Error() string {
if p.col == 0 && p.line == 0 {
return fmt.Sprintf("parse error : %s", p.msg)
}
return fmt.Sprintf("parse error at line %d, col %d: %s", p.line, p.col, p.msg)
}
// Is allows to use errors.Is(err,ErrParse) on this error.
func (p ParseError) Is(target error) bool {
return target == ErrParse
}
func NewParseError(msg string, line, col int) ParseError {
return ParseError{
msg: msg,
line: line,
col: col,
}
}
func NewStageError(expr string, err error) ParseError {
return ParseError{
msg: fmt.Sprintf(`stage '%s' : %s`, expr, err),
line: 0,
col: 0,
}
}
type PipelineError struct {
metric labels.Labels
errorType string
}
func NewPipelineErr(metric labels.Labels) *PipelineError {
return &PipelineError{
metric: metric,
errorType: metric.Get(ErrorLabel),
}
}
func (e PipelineError) Error() string {
return fmt.Sprintf(
"pipeline error: '%s' for series: '%s'.\n"+
"Use a label filter to intentionally skip this error. (e.g | __error__!=\"%s\").\n"+
"To skip all potential errors you can match empty errors.(e.g __error__=\"\")\n"+
"The label filter can also be specified after unwrap. (e.g | unwrap latency | __error__=\"\" )\n",
e.errorType, e.metric, e.errorType)
}
// Is allows to use errors.Is(err,ErrPipeline) on this error.
func (e PipelineError) Is(target error) bool {
return target == ErrPipeline
}
type LimitError struct {
error
}
func NewSeriesLimitError(limit int) *LimitError {
return &LimitError{
error: fmt.Errorf("maximum of series (%d) reached for a single query", limit),
}
}
// Is allows to use errors.Is(err,ErrLimit) on this error.
func (e LimitError) Is(target error) bool {
return target == ErrLimit
}