"""Squid access.log parser and analyzer. Squid native access.log line format (default): time elapsed client action/code size method URL ident hierarchy content-type Example: 1783841223.438 2488 172.16.12.232 TCP_MISS_ABORTED/000 0 GET \ http://169.254.169.254/metadata/instance/compute - HIER_DIRECT/169.254.169.254 - """ from __future__ import annotations import re from collections import Counter, defaultdict from datetime import datetime, timezone from urllib.parse import urlsplit # --- Result code taxonomy --------------------------------------------------- # Squid result codes split into categories for analysis. RESULT_CATEGORIES = { # cache hits "TCP_HIT": "Hit", "TCP_MEM_HIT": "Hit", "TCP_NEGATIVE_HIT": "Hit", "TCP_IMS_HIT": "Hit", "TCP_REFRESH_HIT": "Hit", "TCP_REFRESH_FAIL_HIT": "Hit", "TCP_REF_FAIL_HIT": "Hit", "TCP_IMS_HIT": "Hit", "TCP_DENIED_REPLY": "Denied", # cache misses "TCP_MISS": "Miss", "TCP_MISS_ABORTED": "Aborted", "TCP_REFRESH_MISS": "Miss", "TCP_CLIENT_REFRESH_MISS": "Miss", "TCP_SWAPFAIL_MISS": "Miss", # tunnels / connect "TCP_TUNNEL": "Tunnel", "CONNECT": "Tunnel", # denied "TCP_DENIED": "Denied", "TCP_REDIRECT": "Redirect", "NONE": "Error", # udp "UDP_HIT": "Hit", "UDP_MISS": "Miss", "UDP_DENIED": "Denied", "UDP_INVALID": "Error", "UDP_MISS_NO_FETCH": "Miss", } RESULT_CODE_DESCRIPTION = { "TCP_HIT": "Cache hit - served from cache", "TCP_MEM_HIT": "Memory cache hit", "TCP_NEGATIVE_HIT": "Negative cached (e.g. 404)", "TCP_IMS_HIT": "IMS hit (If-Modified-Since, 304)", "TCP_MISS": "Cache miss - fetched from origin", "TCP_MISS_ABORTED": "Miss - client aborted the request", "TCP_TUNNEL": "CONNECT tunnel established (HTTPS proxy)", "TCP_DENIED": "Request denied by ACL", "TCP_DENIED_REPLY": "Reply denied by ACL", "TCP_REFRESH_HIT": "Revalidation: still fresh", "TCP_REFRESH_MISS": "Revalidation: stale, re-fetched", "TCP_CLIENT_REFRESH_MISS": "Client forced refresh (Ctrl+F5)", "TCP_REDIRECT": "Redirected by redirector", "TCP_SWAPFAIL_MISS": "Swapfile miss (cache corruption?)", "NONE": "Error before request was processed", "UDP_HIT": "ICP cache hit", "UDP_MISS": "ICP cache miss", "UDP_DENIED": "ICP request denied", "UDP_INVALID": "Invalid ICP request", } # hierarchy code -> short label HIERARCHY_LABELS = { "HIER_DIRECT": "Direct (no peer)", "HIER_NONE": "None", "HIER_SIBLING_HIT": "Sibling hit", "HIER_PARENT_HIT": "Parent hit", "HIER_DEFAULT_PARENT": "Default parent", "HIER_SINGLE_PARENT": "Single parent", "HIER_FIRST_UP_PARENT": "First up parent", "HIER_NO_DIRECT_FAIL": "No direct fail", "HIER_SRC_RTT_FASTEST": "Fastest RTT", "HIER_NEAREST_NEIGHBOR_HIT": "Nearest neighbor hit", "HIER_CD_SIBLING_HIT": "CARP sibling hit", "HIER_CD_PARENT_HIT": "CARP parent hit", "HIER_CARPLIST": "CARP list", "HIER_MULTICAST_SIBLING": "Multicast sibling", "HIER_ANY_PARENT": "Any parent", "HIER_INVALID_CODE": "Invalid", } _LOG_LINE_RE = re.compile( r"""^ (?P