107 lines
3.5 KiB
Python
107 lines
3.5 KiB
Python
"""
|
||
precti_trace.py – přehledné SQL dotazy z Firebird audit trace logu
|
||
Čte od konce (nejnovější nahoře).
|
||
|
||
Použití:
|
||
python precti_trace.py # posledních 50 dotazů
|
||
python precti_trace.py 100 # posledních 100
|
||
python precti_trace.py 50 SELECT # filtr – jen SELECT dotazy
|
||
"""
|
||
|
||
import re, sys, io
|
||
|
||
LOG_PATH = r'C:\Program Files\Firebird\Firebird_2_5_CGM\default_trace.log'
|
||
SEPARATOR = '-' * 80
|
||
|
||
TS_RE = re.compile(r'^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d+)\s+\([\w:]+\)\s+(\w+)')
|
||
ATT_RE = re.compile(r'\(ATT_\d+,\s*([\w]+):')
|
||
SQL_S_RE = re.compile(r'^-{70,}$')
|
||
SQL_E_RE = re.compile(r'^\^{70,}$')
|
||
|
||
# ── Parametry ──────────────────────────────────────────────────────────────
|
||
limit = int(sys.argv[1]) if len(sys.argv) > 1 else 50
|
||
filtr = sys.argv[2].upper() if len(sys.argv) > 2 else ''
|
||
|
||
# ── Čtení logu ─────────────────────────────────────────────────────────────
|
||
with open(LOG_PATH, 'r', encoding='cp1252', errors='replace') as f:
|
||
lines = f.readlines()
|
||
|
||
# ── Rozděl log na bloky podle timestamp řádků ──────────────────────────────
|
||
# Každý blok = od jednoho timestamp řádku do dalšího
|
||
blocks = [] # (start_line_idx, ts, event, block_lines[])
|
||
i = 0
|
||
n = len(lines)
|
||
|
||
while i < n:
|
||
m = TS_RE.match(lines[i].rstrip())
|
||
if m:
|
||
ts = m.group(1)
|
||
event = m.group(2)
|
||
start = i
|
||
i += 1
|
||
block = []
|
||
while i < n and not TS_RE.match(lines[i].rstrip()):
|
||
block.append(lines[i].rstrip())
|
||
i += 1
|
||
blocks.append((ts, event, block))
|
||
else:
|
||
i += 1
|
||
|
||
# ── Extrahuj SQL z PREPARE_STATEMENT bloků ─────────────────────────────────
|
||
results = []
|
||
|
||
for ts, event, block in blocks:
|
||
if event != 'PREPARE_STATEMENT':
|
||
continue
|
||
|
||
# Uživatel
|
||
user = '?'
|
||
for line in block:
|
||
att = ATT_RE.search(line)
|
||
if att:
|
||
user = att.group(1)
|
||
break
|
||
|
||
# SQL mezi --- a ^^^
|
||
sql_lines = []
|
||
plan_lines = []
|
||
in_sql = False
|
||
after_sql = False
|
||
|
||
for line in block:
|
||
if SQL_S_RE.match(line):
|
||
in_sql = True
|
||
after_sql = False
|
||
continue
|
||
if SQL_E_RE.match(line):
|
||
in_sql = False
|
||
after_sql = True
|
||
continue
|
||
if in_sql:
|
||
sql_lines.append(line)
|
||
elif after_sql and line.startswith('PLAN'):
|
||
plan_lines.append(line)
|
||
|
||
sql = '\n'.join(sql_lines).strip()
|
||
plan = ' '.join(plan_lines).strip()
|
||
|
||
if sql:
|
||
results.append((ts, user, sql, plan))
|
||
|
||
# ── Výstup – nejnovější nahoře ─────────────────────────────────────────────
|
||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
|
||
|
||
filtered = [r for r in results if filtr in r[2].upper()] if filtr else results
|
||
filtered = list(reversed(filtered))[:limit]
|
||
|
||
print(f'Firebird trace – posledních {len(filtered)} dotazu'
|
||
+ (f' [filtr: {filtr}]' if filtr else ''))
|
||
print(SEPARATOR)
|
||
|
||
for ts, user, sql, plan in filtered:
|
||
print(f'[{ts}] {user}')
|
||
print(sql)
|
||
if plan:
|
||
print(f' --> {plan}')
|
||
print(SEPARATOR)
|