A hands-on look at JJHub OBSERVE's SQL-like log search: automatic field extraction, mixed full-text and structured queries, and aggregation. Includes ready-to-use troubleshooting queries and indexing tips to keep search fast at scale.
When something breaks, an engineer's first instinct is to pull a few key records out of a mountain of logs. Traditional keyword search works right up until you need something like "find every request to /api/order that took longer than 500ms and returned a non-200 status." At that point you're either writing brittle regular expressions or shipping logs off to a separate analysis tool.
JJHub OBSERVE treats logs like a database table and supports SQL-like syntax. You don't have to learn a vendor-specific query DSL — if you can write SQL, you can search. Fields are extracted automatically at ingestion, so WHERE, GROUP BY, and ORDER BY work directly against your data.
The point isn't that the syntax resembles SQL. It's that the query bar drops low enough that the person on call can run an investigation without escalating to a DBA. When an alert fires, whoever answers it can pull the data themselves.
Automatic field extraction. As logs arrive, the system parses JSON fields, key=value pairs, and timestamps into structured fields you can reference directly. Nginx fields like status, request_time, and upstream_addr are queryable out of the box, and nested JSON expands into dotted paths like data.user.id.
Mixed full-text and structured search. message LIKE '%timeout%' and status >= 500 combine in a single query, so you get fuzzy matching and precise filtering together without switching between two search modes.
Aggregation. GROUP BY with count, sum, avg, max, and min returns results in seconds even across hundreds of millions of log lines — no need to move data to an external tool first.
Find slow requests on an interface:
SELECT status, avg(request_time) AS avg_rt, count(*) AS cnt
FROM nginx_access
WHERE request_time > 0.5
GROUP BY status
ORDER BY cnt DESC
Pull errors from a service in the last hour:
SELECT * FROM app_log
WHERE level = 'ERROR'
AND service = 'order-service'
AND timestamp >= now() - INTERVAL 1 HOUR
ORDER BY timestamp DESC
LIMIT 100
See who's hammering your gateway:
SELECT client_ip, count(*) AS cnt
FROM gateway_log
GROUP BY client_ip
ORDER BY cnt DESC
LIMIT 20
From any result set you can jump straight to the correlated trace, or save the query as an alert condition, so you're not tabbing between screens during an incident.
Search speed comes down to indexing. A few rules of thumb we've learned the hard way:
service, level, and status. Don't fully index huge fields like message.WHERE timestamp clause is the cheapest filter you can add, so add it whenever you can.The value of log search isn't just "can it search" — it's whether the people on call can run down an incident without waiting for someone else to pull the numbers. Lowering the query bar to SQL is what keeps alert response moving.