# trace_report.py – Excel report z Firebird audit trace logu # Ulozi do u:\Dropbox\!!!Days\Downloads Z230\, smaze predchozi verzi. import re, sys, io, os, openpyxl from openpyxl.styles import Font, PatternFill, Alignment from openpyxl.utils import get_column_letter from datetime import datetime LOG_PATH = r'C:\Program Files\Firebird\Firebird_2_5_CGM\default_trace.log' OUTPUT_DIR = r'u:\Dropbox\!!!Days\Downloads Z230' 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,}$') HEADER_FILL = PatternFill('solid', fgColor='2F5496') HEADER_FONT = Font(bold=True, color='FFFFFF') ZEBRA_FILL = PatternFill('solid', fgColor='DCE6F1') WRAP_TOP = Alignment(wrap_text=True, vertical='top') # ── Smazání předchozích verzí ─────────────────────────────────────────────── for f in os.listdir(OUTPUT_DIR): if f.endswith('_trace.xlsx'): os.remove(os.path.join(OUTPUT_DIR, f)) # ── Výstupní soubor ───────────────────────────────────────────────────────── now = datetime.now() filename = now.strftime('%Y-%m-%d_%H-%M-%S') + '_trace.xlsx' out_path = os.path.join(OUTPUT_DIR, filename) # ── Čtení logu ───────────────────────────────────────────────────────────── with open(LOG_PATH, 'r', encoding='cp1252', errors='replace') as f: lines = f.readlines() # ── Rozděl na bloky ───────────────────────────────────────────────────────── blocks = [] i, n = 0, len(lines) while i < n: m = TS_RE.match(lines[i].rstrip()) if m: ts, event = m.group(1), m.group(2) 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 user = '?' for line in block: att = ATT_RE.search(line) if att: user = att.group(1) break sql_lines, plan_lines = [], [] in_sql, after_sql = False, False for line in block: if SQL_S_RE.match(line): in_sql, after_sql = True, False continue if SQL_E_RE.match(line): in_sql, after_sql = False, 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: # Detekuj typ dotazu first = sql.lstrip().upper() if first.startswith('SELECT'): typ = 'SELECT' elif first.startswith('INSERT'): typ = 'INSERT' elif first.startswith('UPDATE'): typ = 'UPDATE' elif first.startswith('DELETE'): typ = 'DELETE' elif first.startswith('EXECUTE'): typ = 'EXECUTE' else: typ = 'OTHER' results.append((ts, user, typ, sql, plan)) # Nejnovější nahoře results = list(reversed(results)) # ── Excel ─────────────────────────────────────────────────────────────────── wb = openpyxl.Workbook() ws = wb.active ws.title = 'TRACE' cols = ['CAS', 'UZIVATEL', 'TYP', 'SQL', 'PLAN'] ws.append(cols) for i, (ts, user, typ, sql, plan) in enumerate(results, start=2): ws.append([ts, user, typ, sql, plan]) if i % 2 == 0: for cell in ws[i]: cell.fill = ZEBRA_FILL for cell in ws[i]: cell.alignment = WRAP_TOP # Záhlaví for cell in ws[1]: cell.fill = HEADER_FILL cell.font = HEADER_FONT cell.alignment = Alignment(horizontal='center') # Šířky sloupců for col, width in zip(['A','B','C','D','E'], [22, 12, 10, 80, 60]): ws.column_dimensions[col].width = width # Výška řádků – SQL může být víceřádkový for row in ws.iter_rows(min_row=2): lines_count = max(row[3].value.count('\n') + 1 if row[3].value else 1, 1) ws.row_dimensions[row[0].row].height = min(lines_count * 15, 120) ws.freeze_panes = 'A2' # Autofiltr ws.auto_filter.ref = f'A1:E{len(results)+1}' wb.save(out_path) sys.stdout.buffer.write(f'Ulozeno: {out_path}\n'.encode('utf-8')) sys.stdout.buffer.write(f'Dotazu: {len(results)}\n'.encode('utf-8'))