Stop relying on keywords and regex. This post walks through Jujing OBSERVE's SQL-style log search, covering structured fields, aggregation functions, and three real debugging scenarios so you can locate production issues in seconds.
Most log tools rely on fuzzy keyword matching or regular expressions. A keyword hit doesn't tell you which service produced the line or which user was affected; a regex is painful to write and even worse to hand off to a colleague, because the next person has to reverse-engineer what your pattern was meant to catch. When you're debugging a production incident, what you actually want is something like: "give me every request from the payment service that returned a 5xx in the last five minutes, sorted by latency." That is a query, not a search — and the distinction matters more than it sounds, because a query can be reasoned about, reused, saved, and turned into an alert. Teams stuck on keyword search live with longer MTTR, because every incident starts with the same slow ritual: grep, eyeball raw lines, guess.
The reason logs are hard to query is that they're unstructured text. Jujing OBSERVE fixes this at ingest time: it runs each line through a parser pipeline that handles JSON logs and common Nginx and Java formats out of the box, extracting fields such as level, service, trace_id, status_code, cost_ms, and user_id. For custom formats you can add a Grok pattern or a simple key-value rule, and the fields become queryable immediately. Once logs are structured, you can type SQL-style statements directly in the search box:
SELECT * FROM logs
WHERE service = 'payment'
AND level = 'ERROR'
AND status_code >= 500
AND ts BETWEEN now() - 5m AND now()
ORDER BY cost_ms DESC
LIMIT 100
WHERE, GROUP BY, ORDER BY, and LIMIT are all supported, along with aggregation functions such as count, avg, p95, and sum. p95 deserves special mention: it is far more useful than average for hunting slow requests, because an average is skewed by a handful of extreme outliers while p95 reflects the latency most users actually experience. If your monitoring reports "average latency 40ms" but p95 is 900ms, a small slice of your traffic is having a terrible time and you'd never know it from the mean.
Finding slow endpoints. To see which endpoint in the order service is slowest over the past hour:
SELECT uri, count(*) AS cnt, p95(cost_ms) AS p95
FROM logs
WHERE service = 'order' AND ts > now() - 1h
GROUP BY uri
ORDER BY p95 DESC
This collapses millions of raw lines into a handful of rows, which is exactly the shape you want before drilling into detail.
Correlating errors with traces. When your logs carry a trace_id, a single error line links straight to its distributed trace, showing the full upstream/downstream call order and per-hop latency. You stop guessing which service broke first and start reading the actual call graph — the error line becomes a doorway, not a dead end. This alone removes the most time-consuming step of an incident: figuring out which service is the source, rather than the first one to log an error.
Scoping impact by user. Aggregating by user_id tells you in seconds whether a fault affects one unlucky user or the entire fleet. That single fact usually decides whether you roll back immediately or investigate at leisure, so it's worth making user_id a first-class search dimension from day one.
When logs behave like a queryable table, the gap between "something is wrong" and "here is the exact request" shrinks from hours to minutes.