rg — Log Searching

Log Analysis

rg’s SIMD-accelerated search makes it ideal for filtering large log streams. Use it on the output of journalctl, directly on log files, or across rotated/compressed archives. The key patterns: pipe for live streams, file arguments for on-disk logs, and find + zgrep for compressed rotations.


journalctl | rg — filter systemd journal by pattern with context
journalctl --since '1 hour ago' --no-pager | rg -i 'error|fail' -C 2 | head -30

--no-pager prevents journalctl from invoking less — required for piping. -C 2 adds 2 lines of context above and below each match. rg reads stdin when no file argument is given. This is the bread-and-butter log search.


journalctl | rg -c — count occurrences per pattern
journalctl --since '24 hours ago' --no-pager -p err | rg -c 'error' || echo "0 matches"

-c on a stdin stream gives a single count (no filename prefix). -p err pre-filters to error priority at the journald level, then rg further refines. The || echo "0 matches" handles the case where rg exits 1 (no matches) — which would otherwise look like a failure.


Auth log scanning — failed authentication attempts
journalctl _COMM=sshd --since '24 hours ago' --no-pager | rg -i 'failed|invalid user|refused' | head -20

_COMM=sshd filters to the sshd unit at the journal level — far more efficient than grepping the entire journal. rg then refines to authentication failures. On systems with /var/log/auth.log, use rg -i 'failed password|invalid user' /var/log/auth.log instead.


Error frequency — extract and count unique error patterns
journalctl --since '6 hours ago' --no-pager | rg -oi '[a-z]+ error[: ].*' | sort | uniq -c | sort -rn | head -15

-o prints only the matched text. -i catches case variations. sort | uniq -c | sort -rn is the standard frequency analysis pipeline. The result is a ranked list of unique error messages by occurrence count.


Time-bounded search — constrain journalctl window then filter
journalctl --since '2026-04-11 06:00:00' --until '2026-04-11 12:00:00' --no-pager | rg -i 'denied\|timeout\|refused' | head -20

Always constrain the time window at the journalctl level first — it uses binary search on the journal, which is orders of magnitude faster than piping the entire journal through rg. The rg pattern further refines within that window.


Multi-pattern with -e — match error OR warn OR fail
journalctl --since '1 hour ago' --no-pager | rg -e 'error' -e 'warn' -e 'fail' -i --color=never | head -30

Each -e adds an alternative pattern (logical OR). Cleaner than 'error|warn|fail' when any pattern contains regex metacharacters. --color=never strips ANSI codes — essential when piping output to further processing.


Compressed rotated logs — find + zgrep for .gz archives
find /var/log -name '*.gz' -type f 2>/dev/null | head -5 && echo "---" && find /var/log -name '*.gz' -type f -exec zgrep -l 'error' {} \; 2>/dev/null | head -10

rg cannot read compressed files natively. For .gz rotated logs, find + zgrep is the correct tool. First command lists available archives; second searches them. For uncompressed rotated logs (e.g., syslog.1), rg works directly: rg 'pattern' /var/log/syslog.*.


Access log parsing — extract fields with capture groups
cat <<'EOF' > /tmp/rg-access.log
192.168.1.10 - - [11/Apr/2026:10:15:30 +0000] "GET /api/health HTTP/1.1" 200 45
10.0.0.5 - - [11/Apr/2026:10:15:31 +0000] "POST /api/login HTTP/1.1" 401 89
192.168.1.10 - - [11/Apr/2026:10:15:32 +0000] "GET /api/users HTTP/1.1" 403 120
10.0.0.5 - - [11/Apr/2026:10:15:33 +0000] "POST /api/login HTTP/1.1" 401 89
EOF
rg -Po '(\S+) .* "(\w+) (\S+) .*" (\d{3})' -r '$1 $2 $3 $4' /tmp/rg-access.log

Captures IP, method, path, and status code from combined log format. -Po for PCRE2 + only-match. -r reshapes the output. Pipe to sort | uniq -c | sort -rn for frequency analysis by IP, path, or status code.


Correlate across log sources — same pattern in multiple files
cat <<'EOF' > /tmp/rg-auth.log
Apr 11 10:15:30 host sshd: Failed password for admin from 10.0.0.5
Apr 11 10:15:31 host sshd: Failed password for admin from 10.0.0.5
Apr 11 10:15:32 host sshd: Failed password for admin from 10.0.0.5
EOF
cat <<'EOF' > /tmp/rg-syslog.log
Apr 11 10:15:33 host kernel: [UFW BLOCK] IN=eth0 SRC=10.0.0.5 DST=192.168.1.1
Apr 11 10:15:34 host kernel: [UFW BLOCK] IN=eth0 SRC=10.0.0.5 DST=192.168.1.1
EOF
rg '10\.0\.0\.5' /tmp/rg-auth.log /tmp/rg-syslog.log

rg’s multi-file output includes the filename prefix, making it easy to see which log source each hit comes from. Use this to correlate a suspicious IP across authentication logs, firewall logs, and application logs in a single command.


Rate detection — count matches per time window
cat <<'EOF' > /tmp/rg-rate.log
Apr 11 10:15:01 host sshd: Failed password for root
Apr 11 10:15:02 host sshd: Failed password for root
Apr 11 10:15:03 host sshd: Failed password for root
Apr 11 10:16:01 host sshd: Failed password for admin
Apr 11 10:17:01 host sshd: Failed password for root
Apr 11 10:17:02 host sshd: Failed password for root
EOF
rg -o 'Apr 11 \d{2}:\d{2}' /tmp/rg-rate.log | sort | uniq -c | sort -rn

Extracts the timestamp truncated to the minute, then counts per minute. A spike in the count column indicates a brute-force attempt or service failure burst. Adjust the regex to truncate to hour (\d{2}) or second (\d{2}:\d{2}:\d{2}) as needed.