Queries
Query System: RunReveal uses ClickHouse as its query engine, giving you access to powerful SQL capabilities for analyzing your log data. All queries support parameterized syntax for flexible, reusable query patterns.
Quick Start
Every RunReveal query follows this basic structure with built-in time parameters:
SELECT *
FROM logs
WHERE receivedAt >= {from:DateTime}
AND receivedAt < {to:DateTime}
LIMIT 100Key Points:
- Use
`{from:DateTime}`and`{to:DateTime}`for time filtering (automatically set by the UI) - Always use
receivedAtfor time-based queries (it’s indexed and handles delayed logs) - Include
LIMITto control result size - Use source-specific views like
aws_cloudtrail_logsinstead oflogswhen possible
Built-in Parameters
RunReveal automatically provides time-based parameters that are populated based on your time range selection in the UI.
{from:DateTime} - Start time (inclusive){to:DateTime} - End time (exclusive){interval:UInt32} - Time bucket in seconds{window:UInt32} - Window duration (default: 14400){paramName:Type} syntaxExample Query with Parameters
SELECT
eventName,
srcIP,
COUNT(*) as eventCount
FROM aws_cloudtrail_logs
WHERE receivedAt >= {from:DateTime}
AND receivedAt < {to:DateTime}
AND eventName = 'AssumeRole'
AND srcIP NOT IN ({officeIPs:Array(String)})
GROUP BY eventName, srcIP
ORDER BY eventCount DESC
LIMIT 100Timestamp Fields: receivedAt vs eventTime
Always use receivedAt for time filtering. It’s indexed, handles delayed logs, and ensures consistent query performance across all sources.
✓ receivedAt (Recommended)
⚠ eventTime
Best Practice Example
-- ✅ Good: Uses indexed receivedAt
SELECT *
FROM logs
WHERE receivedAt >= {from:DateTime}
AND receivedAt < {to:DateTime}
AND eventName = 'Login'
-- ❌ Avoid: Uses unindexed eventTime
SELECT *
FROM logs
WHERE eventTime >= {from:DateTime}
AND eventTime < {to:DateTime}
AND eventName = 'Login'Query Optimization
Follow these best practices to write fast, efficient queries:
Query optimized views like aws_cloudtrail_logs instead of the generic logs table.
Apply filters on indexed fields (receivedAt, sourceType, sourceID) first to reduce dataset size before processing.
Start with 1 hour to test, then expand. Shorter windows process much faster than 30-day ranges.
Prevent processing excessive data by including LIMIT in every query.
Prefer COUNT, GROUP BY over returning all individual events.
When querying the logs table, always include sourceType filter.
Common Query Patterns
View Common Query Patterns
SELECT *
FROM logs
WHERE receivedAt >= {from:DateTime}
AND receivedAt < {to:DateTime}
LIMIT 100SELECT eventName, srcIP, eventTime
FROM aws_cloudtrail_logs
WHERE receivedAt >= {from:DateTime}
AND receivedAt < {to:DateTime}
AND eventName = 'AssumeRole'
AND srcIP != ''
ORDER BY eventTime DESC
LIMIT 100SELECT
eventName,
srcIP,
COUNT(*) as eventCount,
min(eventTime) as firstSeen,
max(eventTime) as lastSeen
FROM aws_cloudtrail_logs
WHERE receivedAt >= {from:DateTime}
AND receivedAt < {to:DateTime}
GROUP BY eventName, srcIP
HAVING eventCount > 10
ORDER BY eventCount DESC
LIMIT 100SELECT
toStartOfHour(receivedAt) as hour,
eventName,
COUNT(*) as count
FROM aws_cloudtrail_logs
WHERE receivedAt >= {from:DateTime}
AND receivedAt < {to:DateTime}
GROUP BY hour, eventName
ORDER BY hour DESC, count DESCSELECT
srcIP,
COUNT(*) as eventCount,
count(DISTINCT eventName) as uniqueEvents
FROM logs
WHERE receivedAt >= {from:DateTime}
AND receivedAt < {to:DateTime}
AND sourceType = 'aws_cloudtrail'
GROUP BY srcIP
ORDER BY eventCount DESC
LIMIT 10ClickHouse Functions Reference
View ClickHouse Functions
Complete Reference: RunReveal uses ClickHouse as its query engine. For a complete list of all available functions, see the ClickHouse Functions Documentation.
toYear(), toMonth(), toHour()toStartOfHour(), toStartOfDay()dateDiff(), formatDateTime()match(), LIKE, extract()splitByChar(), upper(), lower()trim(), replace()arrayJoin(), length(), has()hasAny()map[‘key’] - Access map valuesmapKeys(), mapValues()has(map, ‘key’)COUNT(), sum(), avg()quantile(), groupArray()min(), max()if(), multiIf(), coalesce()JSONExtractString(), JSONHas()Common Mistakes to Avoid
❌ Common Mistakes
eventTime for time filteringLIMIT clauselogs without sourceType filterSELECT * with GROUP BY✅ Best Practices
receivedAt for time filteringLIMITsourceType when using logs tableQuick Performance Tips
- Start Small: Test with 1-hour windows before expanding
- Use EXPLAIN: Check execution plans when optimizing
- Monitor Query Time: Watch execution times in the UI
- Index Usage: Filter on indexed columns (receivedAt, sourceType, sourceID)
- Avoid Full Scans: Always include time range filters
- Limit Aggregations: Use LIMIT even with GROUP BY
Related Documentation
- Explore Logs - Learn how to use the query interface
- Writing Detections - Create detection rules from queries
- ClickHouse Documentation - Complete ClickHouse reference
- ClickHouse Functions - All available functions