Format preview worker logs like the main process, tagged with worker pid
Worker stderr is now inherited by the parent, so its log lines land in the server log — but they arrived with the default logging format and a noisy "preview-worker config=..." line at every spawn. - Extract the emoji level-prefix formatting from cista.sanic_logging into cista.util.logformat, which has no Sanic dependency (the worker must not import Sanic: import-time prints could corrupt the stdout protocol). - Worker configures its stderr handler with the same emoji prefixes plus a worker[pid] tag, and the config-loaded info message is removed.
This commit is contained in:
+17
-3
@@ -17,6 +17,7 @@ import gc
|
||||
import io
|
||||
import logging
|
||||
import mimetypes
|
||||
import os
|
||||
import shlex
|
||||
import struct
|
||||
import subprocess
|
||||
@@ -33,9 +34,19 @@ import pyvips
|
||||
from blake3 import blake3
|
||||
|
||||
from cista import config
|
||||
from cista.util.logformat import format_level_prefix
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class _WorkerLogFormatter(logging.Formatter):
|
||||
"""Emoji level prefix like the main process, tagged with the worker pid."""
|
||||
|
||||
def format(self, record: logging.LogRecord) -> str:
|
||||
prefix = format_level_prefix(record.levelno)
|
||||
return f"{prefix}worker[{os.getpid()}]: {record.getMessage()}"
|
||||
|
||||
|
||||
AVIF_FAST_EFFORT = 0
|
||||
|
||||
DOC_PREVIEW_SUFFIXES = {".pdf", ".xps", ".epub", ".mobi"}
|
||||
@@ -554,11 +565,14 @@ def _run_loop() -> None:
|
||||
|
||||
|
||||
def main() -> None:
|
||||
# Configure all log output to stderr before any imports that may emit logs.
|
||||
logging.basicConfig(stream=sys.stderr, level=logging.INFO)
|
||||
# Configure all log output to stderr before any imports that may emit
|
||||
# logs. stderr is inherited by the parent, so this lands in the server
|
||||
# log, formatted like the main process and tagged with the worker pid.
|
||||
handler = logging.StreamHandler(sys.stderr)
|
||||
handler.setFormatter(_WorkerLogFormatter())
|
||||
logging.basicConfig(level=logging.INFO, handlers=[handler])
|
||||
try:
|
||||
config.load_config()
|
||||
logger.info("preview-worker config=%s", config.conffile)
|
||||
except Exception:
|
||||
logger.exception("preview-worker failed to load config at startup")
|
||||
if len(sys.argv) > 1:
|
||||
|
||||
+3
-31
@@ -3,11 +3,13 @@
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
import unicodedata
|
||||
from ipaddress import IPv6Address
|
||||
|
||||
from sanic.log import LOGGING_CONFIG_DEFAULTS
|
||||
|
||||
from cista.util.logformat import EmojiFormatter as _EmojiFormatter
|
||||
from cista.util.logformat import display_width as _display_width
|
||||
|
||||
logger = logging.getLogger("cista.access")
|
||||
|
||||
|
||||
@@ -132,14 +134,6 @@ def format_duration_ms(duration_ms: float) -> str:
|
||||
return f"{hours}h{minutes}m"
|
||||
|
||||
|
||||
def _display_width(text: str) -> int:
|
||||
return sum(
|
||||
1 + (unicodedata.east_asian_width(c) in "FW")
|
||||
for c in text
|
||||
if unicodedata.category(c) != "Mn"
|
||||
)
|
||||
|
||||
|
||||
def _format_left(label: str) -> str:
|
||||
return label[:19].ljust(19)
|
||||
|
||||
@@ -279,28 +273,6 @@ def configure_access_logging() -> None:
|
||||
logger.propagate = False
|
||||
|
||||
|
||||
_LEVEL_EMOJI = {
|
||||
logging.DEBUG: "🔍",
|
||||
logging.INFO: "ℹ️", # noqa: RUF001
|
||||
logging.WARNING: "⚠️",
|
||||
logging.ERROR: "🛑",
|
||||
logging.CRITICAL: "🛑",
|
||||
}
|
||||
|
||||
|
||||
def _format_level_prefix(levelno: int) -> str:
|
||||
emoji = _LEVEL_EMOJI.get(levelno, "▪️")
|
||||
prefix = f"{emoji} "
|
||||
return prefix + (" " * max(0, 3 - _display_width(prefix)))
|
||||
|
||||
|
||||
class _EmojiFormatter(logging.Formatter):
|
||||
"""Compact formatter: emoji + message, no timestamp/level text/logger name."""
|
||||
|
||||
def format(self, record: logging.LogRecord) -> str:
|
||||
return _format_level_prefix(record.levelno) + record.getMessage()
|
||||
|
||||
|
||||
def configure_main_logging() -> None:
|
||||
"""Replace Sanic's verbose 'Main yyyy-mm-dd INFO:' prefix with emoji-only format.
|
||||
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
"""Shared log formatting helpers with no Sanic dependency.
|
||||
|
||||
Used by the main process (cista.sanic_logging) and by the preview worker
|
||||
subprocess, which must not import Sanic.
|
||||
"""
|
||||
|
||||
import logging
|
||||
import unicodedata
|
||||
|
||||
LEVEL_EMOJI = {
|
||||
logging.DEBUG: "🔍",
|
||||
logging.INFO: "ℹ️", # noqa: RUF001
|
||||
logging.WARNING: "⚠️",
|
||||
logging.ERROR: "🛑",
|
||||
logging.CRITICAL: "🛑",
|
||||
}
|
||||
|
||||
|
||||
def display_width(text: str) -> int:
|
||||
return sum(
|
||||
1 + (unicodedata.east_asian_width(c) in "FW")
|
||||
for c in text
|
||||
if unicodedata.category(c) != "Mn"
|
||||
)
|
||||
|
||||
|
||||
def format_level_prefix(levelno: int) -> str:
|
||||
emoji = LEVEL_EMOJI.get(levelno, "▪️")
|
||||
prefix = f"{emoji} "
|
||||
return prefix + (" " * max(0, 3 - display_width(prefix)))
|
||||
|
||||
|
||||
class EmojiFormatter(logging.Formatter):
|
||||
"""Compact formatter: emoji + message, no timestamp/level text/logger name."""
|
||||
|
||||
def format(self, record: logging.LogRecord) -> str:
|
||||
return format_level_prefix(record.levelno) + record.getMessage()
|
||||
Reference in New Issue
Block a user