NOOB2ROOT

Field Guide Detection & monitoring

LogQL

Loki's query language. Pick log streams by label, filter lines, parse out fields, and turn matching lines into counts you can graph and alert on.

#What it is

LogQL is how you ask Loki questions, usually from Grafana's Explore view in Code mode. If you've used Splunk's SPL, the shape will feel familiar: choose the data, filter it, extract fields, then aggregate.

#The building blocks

  • Stream selector: {job="pihole"} picks which logs to read. Always first.
  • Line filter: |= "gravity blocked" keeps lines containing the text (!= excludes, |~ is regex).
  • Parser: | json for JSON lines, or | regexp with named groups like (?P<domain>\S+) for plain text, pulls fields out of each line.
  • Label filter: | src_host != "" filters on an extracted field.
  • Metric query: wrap it in count_over_time(... [24h]), then aggregate with sum by (field) or topk(10, ...).

#Queries I actually use

# Everything Pi-hole blocked
{job="pihole"} |= "gravity blocked"

# Top 10 blocked domains, last 24h
topk(10, sum by (domain) (count_over_time({job="pihole"} |= "gravity blocked" | regexp `gravity blocked (?P<domain>\S+)` [24h])))

# Who is asking for what
{job="pihole"} |= "query[" | regexp `query\[(?P<qtype>\w+)\] (?P<domain>\S+) from (?P<client>\S+)`

# Honeypot hits (skips startup noise)
{job="opencanary"} | json | src_host != ""

The last one, turned into a count over two minutes, is the whole honeypot alert rule:

sum by (src_host, dst_port) (count_over_time({job="opencanary"} | json | src_host != "" [2m]))

#Tips

  • Turn Live off and set a time range while writing queries.
  • Filter lines (|=) before parsing. It's much cheaper to throw lines away early.

← All Field Guide entries