Add agent heartbeat monitoring and fix a query-language lexer bug
Agents now send an independent "still alive" record on a configurable schedule (seconds/minutes/hours, [heartbeat] in agent.toml), separate from real log traffic and tagged with a sentry.heartbeat attribute. No new wire protocol -- it's an ordinary record through the same PushBatch RPC/mTLS identity every log line already uses. Unavailability alerting reuses the existing absence-condition alert rule type unchanged; no new alerting code was needed. See /docs/agent-heartbeat-monitoring.md for the design and how to build the alert rule. While verifying the alert rule live, found that the query language's lexer never treated '-' as part of an identifier, so any unquoted hyphenated filter value -- including the reference doc's own canonical example, `host!=host-03` -- failed to parse at all. Fixed in api/internal/querylang/lexer/lexer.go with regression tests; a leading '-' still lexes as its own token so earliest=-1h/sort -count are unaffected.
This commit is contained in:
@@ -26,6 +26,39 @@ func TestParseSimpleFilter(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestParseFilterWithHyphenatedValue is a regression test for a real
|
||||
// bug in the lexer (isIdentPart excluded '-'): this exact query is
|
||||
// /docs/query-language-reference.md's own canonical unquoted example
|
||||
// and used to fail with "unexpected MINUS after query".
|
||||
func TestParseFilterWithHyphenatedValue(t *testing.T) {
|
||||
q, err := Parse(`host!=host-03`)
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
cmp, ok := q.Base.Terms[0].(ast.Comparison)
|
||||
if !ok {
|
||||
t.Fatalf("expected Comparison, got %T", q.Base.Terms[0])
|
||||
}
|
||||
if cmp.Field != "host" || cmp.Op != "!=" || cmp.Value != "host-03" {
|
||||
t.Fatalf("unexpected comparison: %+v", cmp)
|
||||
}
|
||||
}
|
||||
|
||||
// TestParseNegativeTimeExprStillWorks guards against the hyphenated-
|
||||
// identifier fix above accidentally swallowing the leading sign
|
||||
// earliest=/latest= depend on -- a leading '-' must stay its own token.
|
||||
func TestParseNegativeTimeExprStillWorks(t *testing.T) {
|
||||
q, err := Parse(`earliest=-1h`)
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
earliest := q.Base.Terms[0].(ast.TimeBound)
|
||||
if earliest.Kind != "earliest" || !earliest.Expr.IsRelative || earliest.Expr.RelativeSign != -1 ||
|
||||
earliest.Expr.RelativeN != 1 || earliest.Expr.RelativeUnit != "h" {
|
||||
t.Fatalf("unexpected earliest: %+v", earliest)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseFullPipeline(t *testing.T) {
|
||||
q, err := Parse(`service=api | where status>=500 | stats count(*) as errors by host | sort -errors`)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user