FuseQL examples and use cases :: Kloudfuse Docs

FuseQL examples and use cases

Sample log lines

The examples below are written against these five representative log lines. They cover the most common log shapes you encounter in practice — labeled key=value, structured JSON, free-form text, and delimited records.

nginx access log
A typical web server access log written by nginx or similar reverse proxies. The fields path, status, and duration_ms are key=value facets embedded in the log body, distinct from the source label applied at ingestion.

source="nginx" path=/api/orders status=503 duration_ms=842

Java app log
A structured application log. level and msg are common label/facet names. trace_id links this log line to a distributed trace — useful for correlation across services.

source="orders-service" level="ERROR" msg="Connection refused" trace_id=abc123

Plain text key=value record
An unstructured log line where fields are embedded inline in key=value format. These fields are not indexed at ingestion — you must extract them with a parse operator at query time before you can aggregate or filter on them.

source="payments" user_id=u123 amount=42.50 latency_ms=420

JSON-structured log
A log line whose body is a pure JSON object. source is a label attached by the log shipper at ingestion — it is not part of the log body. level, user.id, and http.status are fields inside the JSON body. Use | json "path" with dot-notation to extract nested fields.

{"level":"warn","user":{"id":"u123"},"http":{"status":500,"path":'/cart/checkout'}}

Delimited record (used by split examples)
A comma-separated audit record with no field names. The raw log body is the CSV — source is a label attached at ingestion and is not included in __kf_msg (the raw message body). Columns are zero-indexed, so column 0 is the timestamp.

2026-06-06T11:23Z,login,u123,success,10.0.0.7

Filtering

Search filters appear before the first | in a FuseQL query. They narrow the set of log lines the pipeline operates on and are evaluated against the index — they do not scan raw log bodies. Filtering early is the single most effective way to keep queries fast.

Two types of fields are filterable before the pipe:

Fields that are only present in the raw log body text (like user_id in the key=value line) cannot be filtered before the pipe — extract them with parse first, then use | where to filter.

Label equality and inequality

Labels are the most efficient filter. They are indexed at ingestion, so equality checks against them incur near-zero scan cost regardless of volume. Always start with a label filter (source=, level=, kube_namespace=) to scope the query before adding any pipe stages.

Match a source exactly — restricts all downstream pipe stages to nginx lines only:

source="nginx"

Exclude a label value. Returns every line in the query window except those from the orders-service:

source!="orders-service"

Combine multiple label filters on the same line — both conditions must be true (implicit and):

source="nginx" level="ERROR"

Facet equality, range, and regex

Facets are structured fields extracted from the log body at ingestion. They support equality, numeric comparison, and regex. Use @ prefix to reference a facet.

Exact match on a string facet — find all activity for a specific user:

@user_id="u123"

Numeric comparison — find slow requests or error responses. Useful for SLO burn-rate queries where you want only the lines that breach a threshold:

@status>=500

Substring, prefix, and suffix

These operators match against field values using positional string checks. They are most useful when you know part of a value but not the full string — for example, filtering API paths by prefix or identifying error classes by suffix.

Substring contains (**) — matches any log line where the label kube_deployment contains the substring:

kube_deployment**"ingress-nginx"

Starts-with (*~) — restricts to paths under /api:

@path*~"/api"

Ends-with (~*) — matches any path ending with /checkout:

@path~*"/checkout"

Free-text terms and grep

FuseQL has two free-text search operators that both scan the full log line — labels and raw message body — but work differently:

Term search (single quotes '…') looks up complete tokens in an inverted index. It is fast and case-insensitive.

Term existence — matches any log line where error appears as a complete token:

'error'

Negated term — excludes any line containing the word healthcheck:

!'healthcheck'

Boolean combinators

Use and, or, and parentheses to express compound conditions.

Scope to nginx lines AND (high-status OR slow response):

source="nginx" and (@status>=500 or @duration_ms>=1000)

Facet existence

Test whether a facet is present. In a log-search query (no aggregation), use the bare @facet form — it matches any line where the facet key exists, regardless of value:

@trace_id

Aggregations

Aggregation operators collapse many log lines into a summary table. They always follow a pipe (|) and are typically the last stage in a query. The by clause breaks results into groups.

Count and distinct count

count answers "how many log lines matched?" — it counts rows, not unique values.

Total log volume bucketed by minute:

* | timeslice 1m | count by _timeslice

count_unique answers "how many distinct values?" — equivalent to COUNT(DISTINCT field) in SQL.: navigate nested objects and bracket notation for arrays.

Scenarios

These scenarios include the query, what to look for in the output, and specific situations where the analysis is useful.

Count all logs
Count the total number of log lines over time, bucketed into 30-second intervals.

source="my-service" | timeslice 30s | count by (_timeslice)

When to use this query:

Count all fingerprints
Kloudfuse clusters log lines into fingerprints — templates that capture the structural pattern of a log line with values replaced by placeholders.

* | timeslice 30s | count_unique(fingerprint) by (_timeslice)

When to use this query:

Count all logs grouped by level
Splitting log count by severity level turns a single total into a stack of signals.

* | timeslice 30s | count by (_timeslice, level)

When to use this query:

Count all fingerprints grouped by source
This query adds a service dimension to fingerprint diversity.

* | timeslice 30s | count_unique(fingerprint) by (_timeslice, source)

When to use this query:

Average of a duration or number facet
Averaging a numeric facet over time produces a performance trend line.

* | timeslice 30s | avg(@duration:duration_seconds) by (_timeslice)

When to use this query:

Anomaly on count of error logs

Threshold-based alerts require you to know in advance what "too many errors" looks like.

core:level="error" | timeslice 120s | count by (_timeslice) | anomaly (_count) by 120s, model=agileRobust, seasonality=hourly, bounds=1, band=3

Outlier detection

Where anomaly detection asks "is this service behaving differently than usual?", outlier detection asks "is this service behaving differently than its peers?".

level="error" | timeslice 120s | count by (_timeslice, kube_namespace) | outlier (_count) by 120s, model=dbscan, eps=3

Log math operator to scale down the Y-axis

When log count varies by orders of magnitude across different services or time periods.

* | timeslice 1m | count as c by (_timeslice, source) | log(c) as log_count