Pretty printing Shibboleth logs

Figuring out problems with Shibboleth can be a daunting task, especially since logs contain many empty fields and it can be hard to tell them apart.

The Python script below reads a Shibboleth log file from standard input and prints every field on its own line.

#
# Set FORMAT to the value specified in shibboleth2.xml
#
# Usage:
# tail -f /var/log/shibboleth/transaction.log | python3 parselog.py
#

import fileinput

FORMAT="%u|%s|%IDP|%i|%ac|%t|%attr|%n|%b|%E|%S|%SS|%L|%UA|%a"

NAMES = {
    "E": "Exception type",
    "S": "Protocol status code",
    "SS": "Protocol sub-status code",
    "s": "Session id",
    "a": "Client address",
    "UA": "Client User-Agent",
    "SP": "SP entityID",
    "IDP": "IdP entityID",
    "b": "Identity protocol binding",
    "n": "Subject identifier of user",
    "u": "REMOTE_USER",
    "i": "Assertion id",
    "t": "Authentication timestamp",
    "ac": "SAML authentication context",
    "L": "Logout result"
}

def lmap(f, l):
    return list(map(f, l))

def lzip(a, b):
    return list(zip(a, b))

def mapFn(x):
    field = x[1:]

    if field in NAMES:
        return NAMES[field]
    return field

fields = lmap(mapFn, FORMAT.split('|'))
fields.insert(0, 'Timestamp')
fields.insert(1, 'Transaction type')

for line in fileinput.input():
    print("")
    for name, value in lzip(fields, line.split('|')):
        print(f"{name:30}: {value}")