Skip to content

Instantly share code, notes, and snippets.

@mjpieters
Created April 21, 2026 16:17
Show Gist options
  • Select an option

  • Save mjpieters/e0b0edff0429c4d1047a9b50be21d251 to your computer and use it in GitHub Desktop.

Select an option

Save mjpieters/e0b0edff0429c4d1047a9b50be21d251 to your computer and use it in GitHub Desktop.
lnav log format definition for fail2ban; requires lnav version 0.14.0 or newer.
{
"$schema": "https://lnav.org/schemas/format-v1.schema.json",
"fail2ban_log": {
"title": "Fail2Ban Actions Log",
"description": "The fail2ban log format",
"url": "https://www.fail2ban.org/",
"multiline": false,
"regex": {
"server-message": {
"pattern": "^(?<timestamp>.*?) fail2ban\\.(?<module>[^ ]+) *\\[\\d+\\]: (?<level>[A-Z]+|#\\d+-Lev\\.) +(?<body>([^[ ]|\\[').*)$"
},
"jail-message": {
"pattern": "^(?<timestamp>.*?) fail2ban\\.(?<module>[^ ]+) *\\[\\d+\\]: (?<level>[A-Z]+|#\\d+-Lev\\.) +\\[(?<jail>[^\\]]+)\\] (?<body>(?:(?<action>(?:Restore |Repeal |Increase )?Ban|Unban|Found|Attempt|Ignore) (?<host>(?:\\d{1,3}\\.){3}\\d{1,3}|(?:::)?(?:[\\dA-Fa-f]{1,4}:{1,2}){1,7}[\\d\\%A-Fa-z\\.]*(?:::)?|::[\\dA-Fa-f\\.]{1,15}|::))?.*)$"
},
"jail-already-banned": {
"pattern": "^(?<timestamp>.*?) fail2ban\\.(?<module>[^ ]+) *\\[\\d+\\]: (?<level>[A-Z]+|#\\d+-Lev\\.) +\\[(?<jail>[^\\]]+)\\] (?<host>(?:\\d{1,3}\\.){3}\\d{1,3}|(?:::)?(?:[\\dA-Fa-f]{1,4}:{1,2}){1,7}(?:[\\d\\%A-Fa-z\\.]+)?(?:::)?|::[\\dA-Fa-f\\.]{1,15}|::) already banned$"
}
},
"opid": {
"description": {
"jail-action": {
"format": [
{"field": "jail"},
{"field": "host"}
]
}
}
},
"level": {
"debug3": "^#\\d+-Lev\\.",
"debug2": "^HEAVY$",
"debug": "^DEBUG$",
"trace": "^TRACE$",
"info": "^INFO|MSG$",
"notice": "^NOTICE$",
"warning": "^WARNING$",
"error": "^ERROR$",
"critical": "^CRITICAL$"
},
"value": {
"module": {
"kind": "string",
"identifier": true,
"description": "The Fail2Ban module responsible for the message"
},
"host": {
"kind": "string",
"collate": "ipaddress",
"identifier": true,
"description": "The host IP address"
},
"action": {
"kind": "string",
"identifier": true,
"description": "The jail action being taken on the host"
},
"jail": {
"kind": "string",
"identifier": true,
"description": "A specific Fail2Ban jail the line applies to"
}
},
"sample": [
{
"line": "2026-04-07 00:02:35,052 fail2ban.actions [850]: NOTICE [sshd] Ban 203.0.113.143",
"level": "notice"
},
{
"line": "2026-04-07 00:06:06,331 fail2ban.filter [850]: INFO [sshd] Found 203.0.113.217 - 2021-03-07 00:06:05",
"level": "info"
},
{
"line": "2026-04-07 00:11:37,892 fail2ban.actions [850]: NOTICE [sshd] Unban 203.0.113.206",
"level": "notice"
},
{
"line": "2026-03-22 00:19:06,126 fail2ban.actions [840]: WARNING [postfix] 185.93.89.64 already banned",
"level": "warning"
},
{
"line": "2026-04-10 16:06:50,352 fail2ban.CommandAction [850]: DEBUG Set add = 'prepend'",
"level": "debug"
},
{
"line": "2026-04-10 16:06:50,352 fail2ban.transmitter [850]: HEAVY ['add', 'prepend']",
"level": "debug2"
},
{
"line": "2026-04-10 16:06:54,756 fail2ban.filter [850]: TRACE Working on line ('', '2026-04-10T15:06:54.482382+00:00 ', 'host.example.com auth[1020193]: pam_unix(dovecot:auth): check pass; user unknown')",
"level": "trace"
},
{
"line": "2026-04-10 16:06:54,757 fail2ban.filter [850]: WARNING [sshd] Detected a log entry 1h before the current time in operation mode. This looks like a timezone problem. Treating such entries as if they just happened."
},
{
"line": "2026-04-10 17:33:30,404 fail2ban.filterpyinotify[2585836]: DEBUG New <Watch wd=1 path=/foo/bar mask=1073745280 proc_fun=None auto_add=False exclude_filter=<function WatchManager.<lambda> at 0xdeadbeef> dir=True >"
},
{
"line": "2026-04-10 17:33:30,408 fail2ban.filterpyinotify[2585836]: MSG Log absence detected (possibly rotation) for /foo/bar/baz.log, reason: INITIAL of /foo/bar/baz.log",
"level": "info"
}
]
}
}
@mjpieters

mjpieters commented Apr 21, 2026

Copy link
Copy Markdown
Author

The combination (jail, host) is registered as operation id (opid), so o / O lets you jump to related lines for the host.

The action column contains the common fail2ban host actions for easy filtering, searching and querying, e.g. Attempt, Found, Ignore, Ban, Unban, Restore Ban, Repeal Ban, and Increase Ban.

To create a per-time period, per-jail report, you will either have to install the pivot virtual table extension for SQLite, or you can manually cover all jails in your query, e.g.:

SELECT
    timeslice(log_time_msecs, '1d') AS log_time_msecs,
    COALESCE(COUNT(*), 0) AS T,
    COALESCE(COUNT(*) FILTER (WHERE jail = 'apache-auth'), 0) AS "apache-auth",
    COALESCE(COUNT(*) FILTER (WHERE jail = 'apache-noscript'), 0) AS "apache-noscript",
    COALESCE(COUNT(*) FILTER (WHERE jail = 'dovecot'), 0) AS dovecot,
    COALESCE(COUNT(*) FILTER (WHERE jail = 'dovecot-spamtraps'), 0) AS "dovecot-spamtraps",
    COALESCE(COUNT(*) FILTER (WHERE jail = 'php-url-fopen'), 0) AS "php-url-fopen",
    COALESCE(COUNT(*) FILTER (WHERE jail = 'postfix'), 0) AS "postfix",
    COALESCE(COUNT(*) FILTER (WHERE jail = 'postfix-spam'), 0) AS "postfix-spam",
    COALESCE(COUNT(*) FILTER (WHERE jail = 'postfix-spamtraps'), 0) AS "postfix-spamtraps",
    COALESCE(COUNT(*) FILTER (WHERE jail = 'sshd'), 0) AS sshd
FROM
    fail2ban_log
WHERE
    action = 'Ban'
GROUP BY
    1
ORDER BY
    1;

or, alternatively, as PRQL:

from fail2ban_log
filter action == 'Ban'
derive log_time_msecs = (time.slice log_time_msecs '1d')
group log_time_msecs (
  aggregate {
    T = count this,
    `apache-auth` = (sum case [ jail == 'apache-auth' => 1 ]),
    `apache-noscript` = (sum case [ jail == 'apache-noscript' => 1 ]),
    `dovecot` = (sum case [ jail == 'dovecot' => 1 ]),
    `dovecot-spamtraps` = (sum case [ jail == 'dovecot-spamtraps' => 1 ]),
    `postfix` = (sum case [ jail == 'postfix' => 1 ]),
    `postfix-spam` = (sum case [ jail == 'postfix-spam' => 1 ]),
    `postfix-spamtraps` = (sum case [ jail == 'postfix-spamtraps' => 1 ]),
    `sshd` = (sum case [ jail == 'sshd' => 1 ]),
  }
)
sort log_time_msecs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment