GQL Query Language Reference

Overview

GQL (GoodLogs Query Language) is a concise, pipeline-based query language for searching logs, aggregating metrics, and defining alert conditions. It compiles directly to optimized SQL.

A GQL query has three parts: filters, a pipeline, and modifiers.

vbnet
severity:error message:~timeout | count by endpoint | top 10 | last:24h

Filters narrow down results. The pipeline transforms them (aggregate, group, sort). Modifiers control time range, limit, and ordering.

Filters

Filters use field:value syntax. Multiple filters are AND'd together.

Exact Match

gql
severity:error
service:billing
status_code:200

Not Equal

gql
severity:!=debug
status_code:!=200

Numeric Comparisons

gql
duration_ms:>500
status_code:>=400
response_time:<100
memory_mb:<=512

Pattern Matching (LIKE)

Use ~ for case-insensitive pattern matching. * is a wildcard.

gql
message:~timeout
message:~"connection refused"
endpoint:~*/api/users*

Negated Pattern

gql
message:!~healthcheck

Regex

gql
message:=~"payment.*failed"
path:=~"^/api/v[23]/"

IN (multiple values)

gql
severity:(error,fatal,warning)
region:(us,eu,ap)

NOT IN

gql
severity:!(debug,info)

Exists / Not Null

gql
has:user_id
field:*

Null Check

gql
error_message:null

All filter operators:

OperatorSyntaxExampleDescription
Equalsfield:valueseverity:errorExact match
Not equalsfield:!=valueseverity:!=debugNot equal
Greater thanfield:>Nduration_ms:>500Numeric >
Greater or equalfield:>=Nstatus_code:>=400Numeric >=
Less thanfield:<Nresponse_time:<100Numeric <
Less or equalfield:<=Nmemory_mb:<=512Numeric <=
LIKE (pattern)field:~patternmessage:~timeoutCase-insensitive pattern (* = wildcard)
NOT LIKEfield:!~patternmessage:!~healthcheckNegated pattern
Regexfield:=~"regex"message:=~"pay.*fail"Regex match
INfield:(a,b,c)severity:(error,fatal)Match any in list
NOT INfield:!(a,b)severity:!(debug,info)Not in list
Existshas:fieldhas:user_idField is NOT NULL
Wildcardfield:*error_code:*Field exists
Nullfield:nullerror:nullField IS NULL
BETWEENfield:lo..hiduration_ms:100..500Range (BETWEEN lo AND hi)

OR Logic

By default all filters are AND'd. Use OR for alternative conditions:

vbnet
severity:error OR status_code:>=500
severity:error service:billing OR severity:fatal OR message:~panic
severity:error OR message:~timeout | count | last:24h

Each OR group is AND'd internally: severity:error service:billing = severity=error AND service=billing.

Nested Field Access

Query nested JSONB properties using dot notation:

makefile
user.address.city:London
request.headers.content_type:application/json
payment.card.brand:visa | count | last:24h

Compiles to: properties->'user'->'address'->>'city' = 'London'

Source Selection

Use from: to specify the data source. If omitted, GQL auto-detects based on filters (e.g., severity: → logs, event_name: → events).

gql
from:logs severity:error
from:events event_name:signup
from:logs+events last:1h
from:logs+alerts last:24h
from:* last:1h
SourceDescription
from:logsApplication logs (severity, message, properties)
from:eventsProduct analytics events (event_name, distinct_id, properties)
from:errorsIndividual captured exceptions (one row per event)
from:issuesGrouped exceptions (one row per fingerprint, with event_count + status)
from:spansDistributed tracing spans (op, status, duration_ms, trace_id, attributes)
from:transactionsAlias for from:spans
from:web_vitalsReal-User Monitoring samples (lcp / inp / cls / fcp / ttfb / …)
from:alertsAlert rules (name, metric, status, severity, threshold, enabled)
from:alert_eventsAlert timeline (event_type, metric, actual_value, alert_name, duration_seconds)
from:X+YUnion of any sources (e.g. logs+events, logs+alerts, events+alert_events)
from:* or from:allEverything (all 4 logs/events/alerts/alert_events sources combined)
(auto)Inferred from filters — severity → logs, event_name → events, event_type → alert_events

Nested attribute access

For sources backed by a JSONB column (spans.attributes, web_vitals_raw.attributes, logs.properties, events.properties), use dotted paths:

gql
from:spans attributes.http.route:/checkout
from:spans attributes.db.system:postgres | count by op
from:web_vitals attributes.tenant:acme metric:lcp
from:logs properties.orderId:ord_123

You can also use properties.x or attributes.x interchangeably — both prefixes are stripped.

Pipeline Stages

count

Count matching rows. Optionally group by a field.

vbnet
severity:error | count
severity:error | count by endpoint
from:events | count by event_name

count_distinct

Count unique values of a field.

csharp
from:events event:signup | count_distinct(distinct_id) | last:7d

sum / avg / min / max

Numeric aggregations. JSONB fields auto-cast to numeric.

scss
| sum(amount) by product | top 10
| avg(duration_ms) by endpoint | last:24h
| min(response_time) | last:1h
| max(memory_mb) by service

Percentiles

p25, p50 (median), p75, p90, p95, p99, or arbitrary pN:

scss
| p50(duration_ms) by endpoint | last:24h
| p90(duration_ms) | timeseries 1h | last:7d
| p95(duration_ms) by service | top 10 | last:24h
| percentile(duration_ms, 42) | last:24h

top N

Limit aggregate results to top N groups (by value descending).

vbnet
severity:error | count by message | top 10

timeseries

Bucket results by time interval for trend visualization.

vbnet
severity:error | count | timeseries 1h | last:7d
from:events | count by event_name | timeseries 1d | last:30d

select

Project specific fields in search mode.

vbnet
severity:error | select severity, message, endpoint, timestamp

distinct

List unique values of a field (SELECT DISTINCT).

sql
| distinct endpoint | last:24h
from:events | distinct event_name | last:7d

as (alias)

Rename the output column of an aggregation.

vbnet
severity:error | count as error_count
| avg(duration_ms) as avg_latency

Conditional Aggregation

Count only rows matching an inline filter. Compiles to SQL FILTER (WHERE ...).

php
| count(severity:error) as errors
| count(status_code:>=500) as server_errors
| count(message:~timeout) as timeouts

Multi-Aggregate

Multiple aggregations in one query with comma separation:

php
from:events event:api_call | count(success:true) as successful, count as total | last:30d
| count(severity:error) as errors, count as total by endpoint | top 10 | last:24h
| count(status_code:>=500) as server_errors, count(status_code:>=400) as client_errors, count as total

Tip: Multi-aggregate is more efficient than running separate queries — it scans the data once.

Modifiers

last (time range)

DurationMeaning
last:5mLast 5 minutes
last:1hLast 1 hour
last:24hLast 24 hours
last:7dLast 7 days
last:30dLast 30 days

limit

vbnet
severity:error limit:100

order

sql
severity:error order:asc
| count by endpoint order:asc
order:endpoint:asc    — sort by specific field

having (post-aggregation filter)

Filter groups after aggregation — only keep groups exceeding a threshold.

sql
| count by endpoint having:>10 | last:24h
| p95(duration_ms) by service having:>500 | last:24h
| count by message having:>=5 | last:24h

Multiple GROUP BY

Group by multiple fields with comma separation.

csharp
| count by severity, endpoint | last:24h
| count by endpoint | timeseries 1h | last:24h  — multi-dimensional timeseries

Let Bindings (Computed Metrics)

Define named sub-queries, combine with math formulas. Compiles to SQL CTEs (WITH ... AS).

css
let a = severity:error | count | last:24h;
let b = | count | last:24h;
a * 100 / b as error_rate

Supports: +, -, *, /, parentheses. Division auto-wraps with NULLIF(x, 0) for safety.

Warning: Let bindings are best for cross-table or complex ratios. For simple conditional counts, prefer multi-aggregate — it's faster (single scan).

Each let binding is a full GQL query with its own filters, time range, and source:

csharp
let success = from:events event:api_call success:true | count | last:30d;
let total = from:events event:api_call | count | last:30d;
success * 100 / total as success_rate

Joins

Join two aggregate results on a shared field. Compiles to SQL JOIN.

vbnet
let errors = severity:error | count by endpoint | last:24h;
let latency = | avg(duration_ms) by endpoint | last:24h;
errors join latency on endpoint | top 10
Join TypeSyntaxBehavior
Innera join b on fieldOnly rows in both
Lefta left join b on fieldAll from a, matching from b
Righta right join b on fieldAll from b, matching from a
Fulla full join b on fieldAll from both, nulls where no match

Tip: Joins work across tables — join log aggregates with event aggregates on a shared field like endpoint, service, or region.

Alert Conditions

sql
severity:error | count | over:30m > 100
severity:fatal | count | over:5m > 0
message:~"payment failed" | count | over:1h > 10
| avg(duration_ms) | over:10m > 2000
from:events | count | over:10m < 1
status_code:>=500 | count | over:5m > 50

Operators: >, >=, <, <=, =, !=

Schema-Aware Autocomplete

The GQL bar provides real-time autocomplete from your project's schema. As you ingest data, GoodLogs discovers property names, types, and example values. Tab to accept, ↑↓ to navigate, Esc to dismiss.

Examples

Log Investigation

vbnet
severity:error last:1h
severity:error service:billing message:~timeout last:24h
severity:!=debug last:1h
severity:error status_code:(500,502,503) last:6h

Event Analytics

csharp
from:events event:signup | count | last:7d
from:events event:page_view | count_distinct(distinct_id) | timeseries 1d | last:30d
from:events event:purchase | count by product_name | top 10 | last:30d
from:events event:subscription | sum(amount) by plan | last:30d

Performance Monitoring

scss
| avg(duration_ms) by endpoint | top 10 | last:24h
| p95(duration_ms) | timeseries 1h | last:7d
duration_ms:>1000 | count by endpoint | top 10 | last:24h

Computed Metrics

vbnet
| count(severity:error) as errors, count as total | last:24h
| count(severity:error) as errors, count as total by endpoint | top 10 | last:24h
let success = from:events event:api_call success:true | count | last:30d;
let total = from:events event:api_call | count | last:30d;
success * 100 / total as success_rate

Alert Rules

sql
severity:error | count | over:30m > 100
from:events | count | over:10m < 1
| avg(duration_ms) | over:10m > 2000
from:events event:login_failed | count | over:10m > 20