Mastering journalctl Pattern Matching for SYSLOG_IDENTIFIER Filtering in Systemd


2 views

When working with journalctl's pattern matching for SYSLOG_IDENTIFIER, many developers encounter unexpected behavior. As shown in the example:

journalctl -t sshd | wc -l
987
journalctl -t 'ssh*'
-- No Entries --

The pattern matching doesn't work as intuitively expected with wildcards. Let's dive deeper into how systemd actually implements pattern matching.

Systemd's pattern matching for SYSLOG_IDENTIFIER follows these rules:

  • Patterns must match the entire identifier string
  • Wildcards (*) are only supported at the beginning or end of patterns
  • The matching is case-sensitive by default
  • Regular expression syntax is not supported in basic pattern matching

Here are several approaches to achieve what you need:

1. Basic Wildcard Matching:

journalctl -t 'sshd*'
journalctl -t '*sshd'

2. Using Multiple Identifiers:

journalctl -t sshd -t ssh

3. Advanced Filtering with Journal Query Language:

journalctl _SYSTEMD_UNIT=sshd.service
journalctl SYSLOG_IDENTIFIER=sshd

For comprehensive SSH log analysis:

# Show all SSH-related logs from today
journalctl -u sshd --since today

# Show failed login attempts
journalctl -t sshd | grep 'Failed password'

# Show logs with PID information
journalctl -t sshd -o verbose

When pattern matching isn't sufficient, consider these alternatives:

# Using grep for more complex pattern matching
journalctl | grep -E 'sshd|ssh'

# Combining multiple filters
journalctl --unit=sshd* --since="1 hour ago"

# Exporting logs for external processing
journalctl -t sshd --output=json > ssh_logs.json

Pattern matching behavior may vary across systemd versions. Always check your version:

journalctl --version
systemd 225

Newer versions (systemd 230+) may support more advanced pattern matching features.


When working with systemd's journal logs, many admins expect -t (or --identifier) to support standard glob patterns for syslog identifier matching. The man page suggests this capability exists, but practical implementation reveals quirks.

Testing with common pattern formats shows limited pattern support:


# Exact match works:
journalctl -t sshd

# Wildcards fail:
journalctl -t 'ssh*'
journalctl -t 'ssh.*'

For broader pattern matching, combine journalctl with grep filtering:


# Basic prefix matching:
journalctl | grep -E '^[A-Za-z]{3} [0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2} .* ssh'

# More precise unit matching:
journalctl _SYSTEMD_UNIT=sshd.service

For true pattern matching across journal fields, use --field:


journalctl --field=_SYSTEMD_UNIT | grep -E '^ssh'

# Combine with JSON output for processing:
journalctl -o json | jq 'select(._SYSTEMD_UNIT | test("^ssh"))'

Pattern matching behavior may vary across systemd versions:


# Check your systemd version:
systemd --version

# Newer versions (v240+) support more advanced filtering:
journalctl -t 'sshd*' --output=json | jq length

When direct pattern matching fails, consider these alternatives:


# List all available identifiers first:
journalctl --field=_SYSTEMD_UNIT | sort -u

# Then filter programmatically:
journalctl -o json | jq -r '._SYSTEMD_UNIT' | grep '^ssh' | uniq