Query Patterns
Common Loki Query Patterns¶
Parsing journald logs¶
# Extract fields from log message using regexp
{service_type="fail2ban"}
| regexp `\[(?P<jail>[^\]]+)\]\s+(?P<action>Ban|Unban)\s+(?P<banned_ip>\d+\.\d+\.\d+\.\d+)`
| action="Ban"
Instant vs Range queries¶
- Instant (
/api/v1/query): Single value per metric, good for tables - Range (
/api/v1/query_range): Time series, good for graphs
Aggregations¶
# Count by label over time window
sum by(jail) (count_over_time({service_type="fail2ban"} [24h]))
# Top N results
topk(20, sum by(banned_ip) (count_over_time(...)))
Loki LogQL Examples¶
Instant Query:
Range Query:
InfluxDB Flux Query Patterns¶
Counter Metrics¶
from(bucket: "telegraf")
|> range(start: v.timeRangeStart, stop: v.timeRangeStop)
|> filter(fn: (r) => r["service"] == "alloy")
|> filter(fn: (r) => r["host"] == "${hostname}")
|> filter(fn: (r) => r["_field"] == "metric_total")
|> derivative(unit: 1s, nonNegative: true)
|> aggregateWindow(every: v.windowPeriod, fn: mean)
Gauge Metrics¶
from(bucket: "telegraf")
|> range(start: v.timeRangeStart, stop: v.timeRangeStop)
|> filter(fn: (r) => r["_field"] == "current_value")
|> aggregateWindow(every: v.windowPeriod, fn: mean)
Multi-Metric Calculation¶
# Calculate percentage from two metrics
hits = from(bucket: "telegraf")
|> range(start: v.timeRangeStart, stop: v.timeRangeStop)
|> filter(fn: (r) => r["_field"] == "cache_hits")
|> set(key: "_field", value: "hits")
misses = from(bucket: "telegraf")
|> range(start: v.timeRangeStart, stop: v.timeRangeStop)
|> filter(fn: (r) => r["_field"] == "cache_misses")
|> set(key: "_field", value: "misses")
union(tables: [hits, misses])
|> pivot(rowKey: ["_time"], columnKey: ["_field"], valueColumn: "_value")
|> map(fn: (r) => ({
_time: r._time,
_value: (r.hits / (r.hits + r.misses)) * 100.0
}))
Panel Type Examples¶
Stat Panel (single value)¶
{
"type": "stat",
"title": "Current Value",
"datasource": {"type": "influxdb", "uid": "${datasource}"},
"targets": [{"query": "...", "refId": "A"}],
"fieldConfig": {
"defaults": {
"unit": "short",
"thresholds": {
"mode": "absolute",
"steps": [
{"value": None, "color": "green"},
{"value": 80, "color": "yellow"},
{"value": 100, "color": "red"}
]
}
}
}
}
Gauge Panel (visual meter)¶
{
"type": "gauge",
"title": "Usage Meter",
"datasource": {"type": "influxdb", "uid": "${datasource}"},
"fieldConfig": {
"defaults": {
"unit": "percent",
"min": 0,
"max": 100,
"thresholds": {
"steps": [
{"value": None, "color": "green"},
{"value": 70, "color": "yellow"},
{"value": 90, "color": "red"}
]
}
}
}
}
Time Series Graph¶
{
"type": "timeseries",
"title": "Metric Over Time",
"datasource": {"type": "influxdb", "uid": "${datasource}"},
"fieldConfig": {
"defaults": {
"unit": "ops",
"custom": {
"drawStyle": "line",
"lineInterpolation": "linear",
"fillOpacity": 10,
"showPoints": "never"
}
}
},
"options": {
"tooltip": {"mode": "multi", "sort": "desc"},
"legend": {
"showLegend": True,
"displayMode": "table",
"placement": "bottom",
"calcs": ["lastNotNull", "max", "mean"]
}
}
}
Fail2ban Journald Migration (2026-01-01)¶
Important: Fail2ban logs migrated from direct file monitoring to journald.
OLD source (deprecated):
- Labels: {job="fail2ban", action_type="Ban", jail="sshd"}
- Pre-parsed by log shipper
- Last data: 2026-01-01 04:18 UTC
NEW source (current):
- Labels: {service_type="fail2ban", hostname="ispconfig3-server.example.com"}
- Log format: [jail] Ban/Unban IP
- Requires regex parsing in queries
- Started: 2026-01-01 04:41 UTC
Query migration example: