Plain-text grid formatter for file/WebSocket logging (no ANSI codes).
| 381 | |
| 382 | |
| 383 | class PlainGridFormatter(logging.Formatter): |
| 384 | """Plain-text grid formatter for file/WebSocket logging (no ANSI codes).""" |
| 385 | |
| 386 | def format(self, record: logging.LogRecord) -> str: |
| 387 | """Format log record into plain text grid layout.""" |
| 388 | try: |
| 389 | req_id = request_id_var.get() |
| 390 | except LookupError: |
| 391 | req_id = " " |
| 392 | |
| 393 | try: |
| 394 | source = source_var.get() |
| 395 | except LookupError: |
| 396 | source = "SYS" |
| 397 | |
| 398 | source_normalized = normalize_source(source) |
| 399 | |
| 400 | now = datetime.now() |
| 401 | timestamp = now.strftime("%H:%M:%S.") + f"{int(now.microsecond / 1000):03d}" |
| 402 | |
| 403 | level_abbrev = Colors.LEVEL_ABBREV.get( |
| 404 | record.levelname, record.levelname[:3].upper() |
| 405 | ) |
| 406 | |
| 407 | id_display = req_id[: Columns.ID].ljust(Columns.ID) |
| 408 | message = record.getMessage() |
| 409 | |
| 410 | # Skip separator lines |
| 411 | if message.strip().startswith("---") or message.strip().startswith("==="): |
| 412 | return "" |
| 413 | |
| 414 | return f"{timestamp} {level_abbrev} {source_normalized} {id_display} {message}" |
| 415 | |
| 416 | |
| 417 | # ============================================================================= |
no outgoing calls