log-search: Add status code search.

This moves log filename parsing after the filter parsing, as that can
now enable --nginx.
This commit is contained in:
Alex Vandiver 2022-05-04 17:32:47 -07:00 committed by Tim Abbott
parent 0bad002c14
commit 8eab5f6931
1 changed files with 21 additions and 5 deletions

View File

@ -2,6 +2,7 @@
import argparse import argparse
import gzip import gzip
import logging
import os import os
import re import re
import signal import signal
@ -56,7 +57,9 @@ def parser() -> argparse.ArgumentParser:
) )
filtering = parser.add_argument_group("Filtering") filtering = parser.add_argument_group("Filtering")
filtering.add_argument("filter", help="IP address, hostname, user-id, or path to search for") filtering.add_argument(
"filter", help="IP address, hostname, user-id, path, or status code to search for"
)
filtering.add_argument( filtering.add_argument(
"--all-lines", "--all-lines",
"-L", "-L",
@ -155,20 +158,29 @@ class FilterType(Enum):
CLIENT_IP = auto() CLIENT_IP = auto()
USER_ID = auto() USER_ID = auto()
PATH = auto() PATH = auto()
STATUS = auto()
def main() -> None: def main() -> None:
args = parser().parse_args() args = parser().parse_args()
logfile_names = parse_logfile_names(args)
# The heuristics below are not intended to be precise -- they # The heuristics below are not intended to be precise -- they
# certainly count things as "IPv4" or "IPv6" addresses that are # certainly count things as "IPv4" or "IPv6" addresses that are
# invalid. However, we expect the input here to already be # invalid. However, we expect the input here to already be
# reasonably well-formed. # reasonably well-formed.
filter = args.filter filter = args.filter
if re.match(r"\d+$", filter): if re.match(r"[1-5][0-9][0-9]$", filter):
string_filter = lambda m: m["code"] == filter
filter_type = FilterType.STATUS
if not args.nginx and filter == "502":
logging.warning("Adding --nginx -- 502's do not appear in Django logs.")
args.nginx = True
elif re.match(r"[1-5]xx$", filter):
filter = filter[0]
string_filter = lambda m: m["code"].startswith(filter)
filter_type = FilterType.STATUS
elif re.match(r"\d+$", filter):
if args.nginx: if args.nginx:
raise parser().error("Cannot parse user-ids with nginx logs; try without --nginx") raise parser().error("Cannot parse user-ids with nginx logs; try without --nginx")
string_filter = lambda m: m["user_id"] == filter string_filter = lambda m: m["user_id"] == filter
@ -199,9 +211,13 @@ def main() -> None:
filter_type = FilterType.PATH filter_type = FilterType.PATH
args.all_lines = True args.all_lines = True
else: else:
raise RuntimeError(f"Can't parse {filter} as an IP, hostname, user-id, or path.") raise RuntimeError(
f"Can't parse {filter} as an IP, hostname, user-id, path, or status code."
)
assert filter_type is not None assert filter_type is not None
logfile_names = parse_logfile_names(args)
try: try:
for logfile_name in reversed(logfile_names): for logfile_name in reversed(logfile_names):
with maybe_gzip(logfile_name) as logfile: with maybe_gzip(logfile_name) as logfile: